Issue with Set-CMTaskSequenceDeployment - sccm

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 :)

Related

How do I prevent users from accidentally deploying to too many tenants in Octopus?

Over the years we’ve had a few instances of Octopus Deploy users accidentally releasing a version to multiple environments, based on a tenant tag.
I usually tell users to check that the Tenant list under ‘Preview and customize’ only contains the 1 environment intended, but we still have some slip through where Octopus deploys to 20+ environments, which I then need to roll back.
Is there a way to alert users when there are more than 1 Tenant in the list, so they can sense check it before proceeding to deploy?
This can be achieved with a PowerShell script, which you add as a deployment step. The script will check for more than one tenant, and alert the user to perform manual intervention if it detects more than 1 target
To have the script work successfully, you must perform the following:
Set a Secret Project Variable named APIKey with the value of an API-Key with access to the deployments within that space.
Change the $octopusURL variable in the Script to match your Octopus Hostname.
Place the Script at the beginning of your deployment inside a "Run A Script" step.
Create a Manual Intervention step as the 2nd process step in your project with the run condition set to: #{Octopus.Action[Run a Script].Output.MultipleTenants}
If you decide to change the name of the step that contains the Script below, be sure to place the step name within the square brackets ([]) on the run condition variable.
$ErrorActionPreference = "Stop";
# Define working variables
$octopusURL = "http://OctopusURL"
$octopusAPIKey = "$APIKey"
$header = #{ "X-Octopus-ApiKey" = $octopusAPIKey }
$spaceId = $OctopusParameters["Octopus.Space.Id"]
# Get Release Deployment Data
$releaseData = Invoke-RestMethod -method GET -uri "$($octopusURL)/api/$($spaceId)/releases/#{Octopus.Release.Id}/deployments/" -Headers $header
# Get DateTime of Deployment Created
$checkDate = Get-Date $OctopusParameters["Octopus.Deployment.Created"] -format "yyyy-MM-dd HH:mm:ss"
write-host "The following tenants are being deployed to at $($checkDate):"
# Instantiate list
$tenantList = #()
# ForEach Deployment Item inside the Release do the following:
foreach($item in $releaseData.Items){
# Generate compatible DateTime for comparison with deployment Time
$date = Get-Date $item.Created.Substring(0,19) -format "yyyy-MM-dd HH:mm:ss"
# Check date equivalence, if equal then do the following:
if($date -eq $checkDate){
write-host "The tenant with ID: $($item.TenantId) is included in this deployment at $($date)."
# Add tenant to list
$tenantList = $TenantList + ($item.TenantId)
# If a release is redeployed, previous tenants may exist in the JSON items, this elseif generates the list of tenants deployed to previously, but not in THIS deployment:
}elseif($tenantList -notcontains $item.TenantId){
write-host "The tenant with ID: $($item.TenantId) is not included in this deployment as it was deployed at $($date)."
}
}
# Condition check list size, create output variable if more than one Tenant.
if($tenantList.Count -gt 1){
Set-OctopusVariable -name "MultipleTenants" -value "True"
}

Cannot find a way to monitor uninstallation of preinstalled Win10 Apps

Currently working on automating the building of some images. I want to have it all documented and have a way to ensure nothing is ever skipped when an image needs created, updated, etc. It will save me a lot of headaches. Below is only the relevant code for this question
Part of uninstalling 'Preinstalled Win10 Apps' is not giving me what I am looking for.
I am not able to accurately see when an 'App' is truly uninstalled.
When it executes Remove-AppxPackage for an App, it will add a progress bar to the top of the PS Window showing its progress and when it completes. It disappears after a while, even if it does not show completed. It will continue to execute behind the scenes but I cannot tell when they are completed. Some are taking longer to uninstall than others.
My goal is find a way to monitor the removal. I cannot find anything built into Remove-AppxPackage for me to do that. I cannot find anything to check against.
I tried wrapping them in jobs using Start-Job, Wait-Job, Remove-Job but that didn't change anything. It was being marked as complete while the uninstall hadn't completed.
Any help or pointing me to a possible solution would be appreciated. Currently I either assume it is done after a lengthy period of time or I rerun the code to see if it tries to process the uninstall.
Testing on a clean install of Win10 Build 1709
List of Apps I am wanting to remove
[System.Collections.ArrayList]$Win10_Apps_To_Uninstall = #(
"Microsoft.BingWeather"
"Microsoft.GetHelp"
"Microsoft.Getstarted"
"Microsoft.Microsoft3DViewer"
"Microsoft.MicrosoftOfficeHub"
"Microsoft.MicrosoftSolitaireCollection"
"Microsoft.Office.OneNote"
"Microsoft.OneConnect"
"Microsoft.People"
"Microsoft.Print3D"
"Microsoft.SkypeApp"
"Microsoft.Wallet"
"microsoft.windowscommunicationsapps"
"Microsoft.WindowsFeedbackHub"
"Microsoft.XboxApp"
"Microsoft.XboxGameOverlay"
"Microsoft.XboxIdentityProvider"
"Microsoft.XboxSpeechToTextOverlay"
"Microsoft.ZuneMusic"
"Microsoft.ZuneVideo"
)
Code to loop through the removal and unprovisioning
foreach ($Win10_App in $Win10_Apps_To_Uninstall) {
try {
Get-AppxPackage -Name $Win10_App -AllUsers | Remove-AppxPackage -Verbose
}
catch {
}
try {
Get-AppXProvisionedPackage -Online |
Where-Object DisplayName -EQ $Win10_App |
Remove-AppxProvisionedPackage -Online -Verbose | Out-Null
}
catch {
}
}

Not able to spawn off email message from windows search in powershell

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.

tailing log file on windows2008 server

I use the following command to tail a logfile on a w2k8 server from a windows8 client pc:
get-content "file" -wait
The log file shows up and it sits there patiently waiting for new lines to be added,
but new lines never show up when they are added.
It worked fine on w2k3 server but somehow tailing on w2k8 server does not work.
The log file is updated from a C# service:
Trace.Listeners.Add(new TextWriterTraceListener(logFileName, "fileListener"));
Trace.WriteLine(....)
Does anybody know what to do about this?
I repro'd the issue on my WS08 system using Trace class. I tried both Trace.Flush() and writing lots of data (100K) and neither caused get-content -wait to respond.
However I did find a workaround. You'd have to update your C# program. (While experimenting I came to the conclusion that gc -wait is pretty fragile.)
$twtl= new-object diagnostics.TextWriterTraceListener "C:\temp\delme.trace",
"filelistener"
[diagnostics.trace]::Listeners.add($twtl)
# This sequence would result in gc -wait displaying output
[diagnostics.trace]::WriteLine("tracee messagee thingee")
[diagnostics.trace]::flush()
# Here I did file name completion such that c:\temp\delme.trace was in the
# completion list.
# In other words I typed something like d and pressed tab
# And this worked every time
# After searching for quite a while I finally found that
# get-itemproperty c:\temp\d*
# produced the same effect. The following sequence always worked:
# (without requiring a tab press)
[diagnostics.trace]::WriteLine("tracee messagee thingee")
[diagnostics.trace]::flush()
get-itemproperty c:\temp\d*
# To finish up
[diagnostics.trace]::Listeners.remove($twtl)
$twtl.close()
$twtl.dispose()
I think there's a bug somewhere. I suggest filing it on the Connect website.

MTM : Is there a way to find test run completion status using command line utility tcm.exe

I use MTM (Microsoft test manager) for running my automated test cases.
I schedule test runs using tcm /create command (trigerred from a powershell script) and once the test run is completed I need to copy the trx (result) file on my local machine. So I want to wait till the test run is completed in some sort of polling mechanism.
Hence, I need a command to fetch the current test run status using test runid. Is there a way to get MTM test run status in this way?
I don't think this is possible. The available switches for run option are:
delete
abort
export
list
create
publish
The only data you can take about runs using /list is
Id
Title
Owner
Date Completed
you can see this by running:
tcm run /list /planid:<plainId> /collection:<CollectionUrl> /teamproject:<TeamProject>
Moreover, you don't have the runId yet so even if there was an option to get the completion status, in your case that would not be easy.
So, I think you should start looking for another solution. Perhaps the TFS Api is what you need.
Check these links:
Automation test run creation using tfs api
TFS 2010 API - Get Results of a Test Run
You can actually get the test id - its what is printed out as a result of tcm.exe run /create command
in powershell it would be something like this:
$testRunSubmitResult = .$tcmPath run /create ......
$testID = $testRunSubmitResult -match "[0-9]{1,1000}"
(i excluded the error handling logic which needs to be present in order to verify that the run was submitted)
after that you can do the following thing - you can export the test run with the used id, and if the test didnt finish yet, you will get and error.
do
{
Start-Sleep -s 60
$testResults = .$tcmPath run /export /id:$testID /resultsfile:$args /collection ....
if(Test-Path $args[0])
{
break
}
if($testResults.GetType() -eq #("1").GetType())
{
if($testResults[1].Contains("Completed export"))
{
break
}
}
if ($testResults.Contains("Completed export"))
{
break
}
}
while ($True)
This is not perfect as it might fail in test runs with big attachments (such as ones produced by the Video data collector) but it might be a solution for some of you
Or alternatively from powerscript you can just use the TFS API like this:
Add-Type -AssemblyName "Microsoft.TeamFoundation.Client, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"Microsoft.TeamFoundation.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"Microsoft.TeamFoundation.TestManagement.Client, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
$tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection("http://tfs:8080/tfs/Collection")
$tfs.EnsureAuthenticated()
$testManagementService = $tfs.GetService([Microsoft.TeamFoundation.TestManagement.Client.ITestManagementService])
$testManagementTeamProject = $testManagementService.GetTeamProject('Project');
do
{
Start-Sleep -s 60
$testRun = $testManagementTeamProject.TestRuns.Find($testId);
if($testRun.State -eq 'Completed')
{
break
}
if($testRun.State -eq 'NeedsInvestigation')
{
break
}
if($testRun.State -eq 'Aborted')
{
break
}
}

Resources