I have a powershell script that is searching the Windows Search index directly for emails and files. I have the following code:
$searchme="my thing to find"
$sql="SELECT System.FileName, System.ItemPathDisplay, System.DateCreated, System.DateModified, system.itemurl, system.itemtypetext FROM SYSTEMINDEX WHERE Contains(System.FileName, '"+$searchme+"') OR Contains('"+$searchme+"')"
$adapter = new-object system.data.oledb.oleDBDataadapter -argumentlist $sql, "Provider=Search.CollatorDSO;Extended Properties=’Application=Windows’;"
$ds = new-object system.data.dataset
$adapter.Fill($ds)
foreach ($record in $ds.Tables[0].Rows)
{
$exeparams = $record[4]
write-host $exeparams
write-host $exeparams.split(":")[0]
if ($exeparams.split(":")[0] -eq "mapi15")
{
$exeparams2="mapi://" + $exeparams.substring(8)
}
write-host $exeparams
write-host "start"
$exe="start"
$exe+" "+$exeparams | Out-File 'file.txt' -encoding Unicode
write-host "start-process"
Start-Process $exeparams
Start-Process $exeparams2
write-host "andpersand process"
&$exe $exeparams
&$exe $exeparams2
write-host "dotnet"
$proc = [Diagnostics.Process]::Start($exeparams)
$proc.WaitForExit()
$proc = [Diagnostics.Process]::Start($exeparams2)
$proc.WaitForExit()
}
There are several "shell" calls because I was trying to figure out if it was a process spawning issue. Files work with no issue. Emails however fail with either No such interface if i leave mapi15, or Unspecified error if i change mapi15 to mapi. I believe that Open mails in outlook from java using the protocol "mapi://" may be the solution, but if it is I am not sure how to apply this in powershell. Thank you for your help.
Ok, that took more work than I expected, and I blame Office 2013 for it. Here's the short answer:
$exeparams2 = $exeparams -replace "^mapi15", "mapi"
& start $exeparams2
That is the code that now opens an email for me. That code did not do that yesterday, all it did is tell me:
Either there is no default mail client or the current mail client cannot fulfill the messaging request. Please run Microsoft Outlook and set it as the default mail client.
Infuriating is what this was, because I did have Outlook, in fact it was running, and was the default mail application for everything email related. This annoyed me, and sent me on a quest to figure out WTF was wrong, and if I could fix it. The answers to that are "I'm not real sure WTF was wrong, except maybe a naming change on MS's part", and "yes, yes I can fix it".
I finally found the fix that worked for me (and I believe that this is probably Office 2013/Office 365 specific) was found at the bottom of this thread:
https://social.technet.microsoft.com/Forums/office/en-US/64c0bedf-2bcd-40aa-bb9c-ad5de20c84be/cannot-send-email-with-microsoft-outlook-2010-64-bit-from-adobe-outlook-not-recognised-as?forum=outlook
The process is simple. Change 2 Registry Entries, then re-set your default mail application. Registry entries:
HKLM:\Software\Clients\Mail(default)
HKLM:\Software\Clients\Mail\Microsoft Outlook(default)
Change the value of (Default) from "Microsoft Outlook" to simply "Outlook".
After that I set Outlook to be the default for everything it could be ( in Win8 that's Control Panel > All Control Panel Items > Default Programs > Set Default Programs then select Outlook, and choose the first option to make it default for all extensions that it is registered for). Once that was done I was able to run the modified code above to launch an email that I had search the index for.
Related
Seems that New-CMTaskSequenceDeployment / Set-CMTaskSequenceDeployment cmdlet option -DeploymentOption does not work as expected.
I'm trying to automate a Task Sequence Deployment via Powershell. I use New-CMTaskSequenceDeployment cmdlet to create the deployment. The content of the TS should be downloaded before the start of the TS.
Works ok, but the -DeploymentOption DownloadAllContentLocallyBeforeStartingTaskSequence seems not to have any effect, when I check the deployment after the script ran, the option "pre-download content for this task sequence" isn't checked.
Same issue when I try Set-CMTaskSequenceDeployment.
Any hint from the community what I'm doing wrong?
...
# Create deployment for all waves now
foreach ($StrCollectionName in $ArrCollectionName)
{
$SchedulePhase2 = New-CMSchedule -Nonrecurring -Start $DateScheduleStartPhase2
Try {
$Deployment = New-CMTaskSequenceDeployment -CollectionName $StrCollectionName -TaskSequencePackageId $StrTaskSequenceID -DeployPurpose Required -AvailableDateTime $DateAvailablePhase1 -DeploymentOption DownloadAllContentLocallyBeforeStartingTaskSequence -SoftwareInstallation $False -SystemRestart $False -Schedule $SchedulePhase2 -RerunBehavior RerunIfFailedPreviousAttempt -AllowUsersRunIndependently $True -SendWakeUpPacket $True
Write-Host "Success - Deployment $Deployment created!"
}
Catch {
Write-Host "Error - Exception caught in creating deployment : $error[0]"
Exit
}
}
...
Looks like unfortunately (and unexpected) the pre-download behavior is different for package/program deployment and task sequence deployment.
In case of a package/program deployment the content download will start after start time in case the deployment has a mandatory time defined.
A TS deployment behaves different. It will start download when mandatory time (schedule) has been reached. Start time will be ignored.
This difference is independently from how the deployment has been started (Console or powershell cmdlet) therefore it is not an issue of the cmdlet.
First of all, you can check the picture below to make sure not to confuse these two options.
Difference between Preload content checkbox and Download all content locally before starting TS
Once done Here is my proposition :
Just by clicking, try to retrieve the property of you TSDeployment before and after you clicked the checkbox. You will see that one property changed. AdvertFlags
PS MUZ:\> (Get-CMTaskSequenceDeployment -DeploymentID MUZ200C5).AdvertFlags
[Convert]::ToString((Get-CMTaskSequenceDeployment -DeploymentID MUZ200C5).AdvertFlags,2)
Output :
34275328
10000010110000000000000000
From there, you can read from the MS doc : https://learn.microsoft.com/en-us/configmgr/develop/reference/core/servers/configure/sms_advertisement-server-wmi-class
From this, I learn that I need to change the 12th bit like this :
$advertflag = Get-CMTaskSequenceDeployment -DeploymentID MUZ200C5
$advertflag.AdvertFlags = $advertflag.AdvertFlags -bor "0x00001000"
$advertflag.put()
I hope it will help someone someday :)
I am planning to deploy Windows 10 using SCCM 2012. It is working fine, and now I just want to rename the computer to be same as its DELL service tag, and make it as part of Task Sequence. I would ideally like to use Powershell script to do so, however happy to use VBS as well, in case it isn't easy enough with PS.
Following is the Powershell script that does the job, however I can't add it as part of Task Sequence!
$sTag = Get-WmiObject -Class win32_BIOS | Select SerialNumber
$cName = 'DESKTOP' + $sTag.SerialNumber
Rename-Computer -NewName $cName
Can someone please assist?
Thanks in advance.
I think you would be better off not renaming the computer after it is already present in sccm and ad but give it a proper name before it is joined (assuming you use unknown computer support for the osd here)
In this case you should set the SCCM Variable OSDCOmputerName already within the WinPE phase like this (you can find more detailed examples e.g. here):
$sTag = Get-WmiObject -Class win32_BIOS | Select SerialNumber
$OSDComputerName = 'DESKTOP' + $sTag.SerialNumber
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$TSEnv.Value("OSDComputerName") = $OSDComputerName
If you want to use powershell in PE you will have to modify your boot image (Right click --> Properties --> Optional Components) to include "Windows PowerShell"
I am wondering if there is anyway to create shelvesets (backup) automatically (e.g. every 1 hr) from open solutions from different workspaces in visual studio?
Here is a extension create a shelveset for the latest version of all pending changes automatically in VS Marketplace.
TFS Auto Shelve for Visual Studio 2015
By default it's 5 minute interval, you could set interval for 60 minutes to meet your needs.
If you dont want the requirement of having VS and a specific solution open, then there's this script I wrote a long time ago and still gets a lot of use.
<#
.DESCRIPTION
This script will create a shelveset for each workspace it finds in the form "WorkspaceName_dddHHmm"
(ex. 'MyWorkspace_Mon1300' for monday at 1PM/1300). It does NOT require Visual Studio to be running.
.NOTE
The intention is to run this as a Scheduled Task periodically. I run it every hour during my usual working
time, and an hour before and after. With the naming pattern it uses, this means I have a rolling week of
shelvesets that I can refer back to in case of hardware failure, mucking something up, getting work laptop
confiscated by TSA, etc. Its also good for teams to use for sharing code or to check on the progress of
noobs that may not know when to ask for help
#>
$ErrorActionPreference = 'Stop'
$Error.Clear()
Clear-Host
#the collection should be read from somewhere like $HOME\AppData\Roaming\Microsoft\VisualStudio\15.0_f40892c4\Team Explorer\TeamExplorer.config
#but this was easier. This URL is for Azure DevOps, for on premise, use the project collection url you can get from looking at the workitems.
$projectCollectionUrl = "https://yourOrgUrl.visualstudio.com"
try
{
$vsWherePath = Resolve-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$tfExeRoot = & "$vsWherePath" -latest -products * -requires Microsoft.VisualStudio.TeamExplorer -property installationPath
$tfExePath = Join-Path $tfExeRoot "\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe" -Resolve
$workspaces = [xml](& $tfExePath vc workspaces /collection:$projectCollectionUrl /format:xml)
$workspaceFolders = #($workspaces.Workspaces.Workspace.Folders.WorkingFolder.local)
$currentDate = (Get-Date).ToString("ddd_HHmm")
foreach($workspace in $Workspaces.Workspaces.Workspace)
{
$workspaceFolder = $workspace.Folders.WorkingFolder.local | Select-Object -First 1
if (-Not (Test-Path $workspaceFolder))
{
Write-Host "There is no workspace folder at $workspaceFolder" -ForegroundColor Red
continue
}
Set-Location $workspaceFolder
try
{
$shelveSetName = "AutoShelve_$($workspace.Name)_$currentDate"
& "$tfExePath" shelve $shelveSetName /noprompt /replace
}
catch
{
if ($_.Exception.Message -like "*There are no matching pending changes to shelve*")
{
Write-Host "There are no pending changes to shelve for workspace $workspaceFolder" -ForegroundColor Yellow
continue
}
throw
}
}
}
finally
{
Set-Location $PSScriptRoot
}
I am having below script:
$pattern = 'Unable to authenticate user!'
$events = Get-WinEvent -ea SilentlyContinue `
-ProviderName "Windows DB Controller - Task Manager Service"|
Where-Object { $_.TimeCreated -gt [datetime]::today -and $_.Message -match $pattern }
$events >> D:\Error.txt
if ($events) {
Send-MailMessage -SmtpServer smtp.domain.com -From No-reply#domain.com -To sunny#domain.com -Subject 'Error found in log' -Body $events
}
I had scheduled it to run on every 10 mins and purposely ,I wanted to achieve following point using above script:
Search the specified error message in the event viewer log only for current-date and as soon as the error message encountered send a email notification to me but didn't want to receive email notification for the error message which appreared today and for which I had already been notified (I mean , wanted to receive error-notification only once for a specific time of current day).
But problem I am facing here is: Getting multiple notifications for same error message for which already being notified.
I hope I am clear enough to put my exact problem.
Could you please help me out, how to resolve this problem ?
If you are running the script every 10 minutes, I would change the condition on the Where-Object so instead of getting all of the events that are "today"; I would change it to get only the events that happened in the last 10 minutes. i.e. the code becomes:
Where-Object { $_.TimeCreated -gt [datetime]::now.AddMinutes(-10) -and $_.Message -match $pattern }
Have a look at this thread:
Powershell - Tail Windows Event Log? Is it possible?
It's on tailing an event log, but the same method should work for what you're tyring to do. Just save the last index number to a file between runs.
How about the following approach:
Register-WmiEvent -Query "select * from __InstanceCreationEvent where TargetInstance ISA 'Win32_NTLogEvent' and TargetInstance.SourceName = 'Windows DB Controller - Task Manager Service' and TargetInstance.Message LIKE '%Unable to authenticate user!%'" -SourceIdentifier "MyEventListener" -Action {
#Your actions
write-host "$($eventargs.NewEvent.TargetInstance.RecordNumber) at $($eventargs.NewEvent.TargetInstance.TimeGenerated)"
}
It uses WMI to subscribe to the event that occurs when an eventlog entry is generated with your criterias. The action itself will only return the new object(so no more duplicates). I've included a sample action to help you understand how to access the object. This method will give you live monitoring.
Inside the action, $eventargs.NewEvent.TargetInstance will give you the object which is an instance of win32_ntlogevent. To see properties of this class, check out TechNet or run the following command:
([wmiclass]'win32_ntlogevent').Properties | ft Name
To make the script run forever, just call your script with powershell -file script.ps1 -noexit or include a while($true) loop at the end of your script. (I'm not sure how the while-loop will affect resource usage longterm, you'd have to test).
I am trying to use powershell to script some tasks within internet explorer. This involves downloading a file from a website after logging in to the site. I have one working test script, but the same code for the actual site gives me this error:
The '=' operator failed: The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED)).
At U:\PowershellScriptProjectSFTP\test.ps1:71 char:22
+ $controlRef = <<<< $browserDoc.getElementByID($controlID)
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : OperatorFailed
$browserDoc
$ie = new-object -com "InternetExplorer.Application"
$ie.navigate("about:blank")
$ie.visible = $true
[System.Threading.Thread]::Sleep(2000)
$ie.navigate($URL)
#get controls
write-host "Getting Document"
$browserDoc=$ie.Document
write-host "Getting Email component"
$email = $browserDoc.getElementById("MainContent_userEmail")
write-host "Getting Password component"
$pass = $browserDoc.getElementById("MainContent_userPassword")
write-host "Getting Button component"
$login = $browserDoc.getElementById("MainContent_submitButton")
The actual error is occuring elsewhere in the code, which I have left out because it is doing the same thing as up here, but during the loop to ensure the page is done loading. This code has worked from the same machine on a different site, but both were .net aspx 2.0 sites.
Basically, once the internet explorer navigates to the specified url, powershell loses the ability to communicate with the object, and this error is followed by several InvokeMethodOnNull and PropertyNotFound errors (these I understand, they are a result of referencing $ie, which has become a null object, the entire problem I am trying to diagnose). I am running Windows 7. Microsoft claims to have a fix for this, but only for XP and Server 03 and 08.
Really, just any explaination for what causes this behavior is all I am looking for. As I said, this same code pointed to some websites works perfectly, and at others fails everytime.
Just ran into this myself and found that running the Powershell window "as administrator" fixed the problem.