Change status of Lync by script - lync-2010

Is it possible to change status of Microsoft Lync 2010 by script?
I want Script which works on Win XP and change status to available after fixed interval.Tried to search in internet but was not successful in finding one.

According to the documentation, the Lync binary does not offer that feature. However, you could use the Lync SDK to achieve what you want by writing a small helper application (or incorporating the relevant code in your current application).
According to an MVP in the Microsoft forums, this also is not available out-of-the-box.
However, according to the documentation, a PowerShell script like this one should be able to do the trick:
import-module "C:\Program Files (x86)\Microsoft Lync\SDK\Assemblies\Desktop\Microsoft.Lync.Controls.Dll"
$availability = [Microsoft.Lync.Controls.ContactAvailability]::Available
$contactInfo = new-object 'System.Collections.Generic.Dictionary[Microsoft.Lync.Model.PublishableContactInformationType, object]'
$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::Availability,
$availability)
$ar = $self.BeginPublishContactInformation($contactInfo, $null, $null)
$self.EndPublishContactInformation($ar)
This script requires the Lync SDK or the Lync SDK redistributable to be installed.
Much of this information has been taken from here.

The above post does not work. More DLL modules are needed. But i've made the following changes below so it works. Then you can use TaskSch to get it to run automatically. Still needs the 2010 Lync SDK installing.
Set 15550 to mean 'Off-Work' not 'Away'. More useful.
See - http://blogs.technet.com/b/heyscriptingguy/archive/2012/08/11/weekend-scripter-use-the-windows-task-scheduler-to-run-a-windows-powershell-script.aspx
Note this code does not check if LYNC is signed in. If it is not it will not run.
import-module "C:\Program Files (x86)\Microsoft Lync\SDK\Assemblies\Desktop\Microsoft.Lync.Controls.Dll"
import-module "C:\Program Files (x86)\Microsoft Lync\SDK\Assemblies\Desktop\Microsoft.Lync.Model.Dll"
# Obtain the entry point to the Lync.Model API
$client = [Microsoft.Lync.Model.LyncClient]::GetClient()
$self = $client.Self;
#Set Details of Personal Note and Availability
#Useful availability codes for use below - 3500 Available, 15500 Away (converted to "Off Work" in this script by setting activity ID), 6500 Busy, 9500 Do not disturb, 12000 Be Right Back)
$availability = 3500
$date = [DateTime]::Now
$message = "Remote Work. UK Time +5 hours EST (US), -5.5 IST (India). Availability script last run $date"
#Publish personal note and presence availability of the local user
$contactInfo = new-object 'System.Collections.Generic.Dictionary[Microsoft.Lync.Model.PublishableContactInformationType, object]'
$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::PersonalNote,
$message)
$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::Availability,
$availability)
If ($availability -eq 15500) {$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::ActivityId,
"off-work")}
$ar = $self.BeginPublishContactInformation($contactInfo, $null, $null)
$self.EndPublishContactInformation($ar)

Ok - This is what I did
Install 2013 SDK (This works with Skype for Business too BTW)
use the code from Pete above except change the assemblies directories to C:\Program Files (x86)\Microsoft Office\Office15\LyncSDK\Assemblies\Desktop\ for both of those
I had to add config files per this page (run as administrator http://tfl09.blogspot.com/2010/08/using-newer-versions-of-net-with.html
Change the message in the script of Pete's
Automate with Task Scheduler the .ps1 script

For Lync 2013 this PowerShell script works. You'll need to install the Lync 2013 SDK first. The SDK installer might say you need to install Silverlight 4, but don't worry about that, it's not necessary.
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process -Confirm:$false
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser -Confirm:$false
Import-Module "C:\Program Files\Microsoft Office\Office15\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.dll"
Import-Module "C:\Program Files\Microsoft Office\Office15\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Controls.dll"
$client = [Microsoft.Lync.Model.LyncClient]::GetClient()
$availability = [Microsoft.Lync.Controls.ContactAvailability]::Away
$contactInfo = (New-Object "System.Collections.Generic.Dictionary[Microsoft.Lync.Model.PublishableContactInformationType,object]") -As "System.Collections.Generic.IEnumerable[System.Collections.Generic.KeyValuePair[Microsoft.Lync.Model.PublishableContactInformationType,object]]"
$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::Availability, $availability)
$ar = $client.Self.BeginPublishContactInformation($contactInfo, [System.AsyncCallback]$null, [object]$null)
$client.Self.EndPublishContactInformation($ar)
That sets the status to "Appear Away", but you can change [Microsoft.Lync.Controls.ContactAvailability]::Away into this [Microsoft.Lync.Controls.ContactAvailability]::None to reset the status.

Related

TASK Names for Visual Studio Code for Windows System Installer script in Powershell

Looking for some help on writing a PowerShell script to install Visual Studio Code.
I have downloaded the Windows 64 System installer: VSCodeSetup-x64-1.56.2
My script so far:
$fullPath = <<Installer location>>
$vscApp = "VSCodeSetup-x64-1.56.2"
$appPath = join-path $fullPath $vscApp
Write-Host "App Path" $appPath
$arguments = '/SILENT /ALLUSERS /mergetasks="!runcode,????, ????, ???? ,????"'
Start-Process $appPath $arguments -Verb RunAs -Wait
I need the list of internal names for all of the check box items on the "Select Additional Tasks"
Select Additional Tasks GUI Screenshot
I want to turn on all four other tasks, both Add Open, Register code, and Add to Path. Only 1 of which seems to be default. While I do not need the desktop icon, from the Inno Setup docs, https://jrsoftware.org/ishelp/index.php?topic=setupcmdline, I can see the desktop Icon name is desktopicon. How and where would I find this list?
Thanks for any and all help!
Continuing from my comment.
There are several pre-built scripts, in several GitHub Repos for silent installs:
Example:
#Install-VSCode
# Download URL, you may need to update this if it changes
$downloadUrl = "https://go.microsoft.com/fwlink/?LinkID=623230"
# What to name the file and where to put it
$installerFile = "vscode-install.exe"
$installerPath = (Join-Path $env:TEMP $installerFile)
# Install Options
# Reference:
# http://stackoverflow.com/questions/42582230/how-to-install-visual-studio-code-silently-without-auto-open-when-installation
# http://www.jrsoftware.org/ishelp/
# I'm using /silent, use /verysilent for no UI
# Install with the context menu, file association, and add to path options (and don't run code after install:
$installerArguments = "/silent /mergetasks='!runcode,addcontextmenufiles,addcontextmenufolders,associatewithfiles,addtopath'"
#Install with default options, and don't run code after install.
#$installerArguments = "/silent /mergetasks='!runcode'"
Write-Verbose "Downloading $installerFile..."
Invoke-Webrequest $downloadUrl -UseBasicParsing -OutFile $installerPath
Write-Verbose "Installing $installerPath..."
Start-Process $installerPath -ArgumentList $installerArguments -Wait
Write-Verbose "Cleanup the downloaded file."
Remove-Item $installerPath -Force
You can also automate installing VSCode extensions.
Example:
Visual Studio Code: Getting Started with PowerShell
https://social.technet.microsoft.com/wiki/contents/articles/35780.visual-studio-code-getting-started-with-powershell.aspx
code --install-extension ms-vscode.powershell

Automate Microsoft Teams Tab App in AzurePipelines

We are trying to automate a Teams Tab App in our Azure Pipeline, but we are wondering if this even possible. We have already created the zip file for the app which can be uploaded via App Studio and it works. But we don't want the customers to do that via App Studio, instead, we want to automate this process on their pipeline. For that we created the following powershell:
# Generate zip file for deployment
$compress = #{
Path = "color.png", "outline.png", "manifest.json"
CompressionLevel = "Fastest"
DestinationPath = "app.zip"
}
Compress-Archive #compress -Update
Then we check if MicrosoftTeams module is installed, otherwise we install it:
# Checks whether MicrosoftTeams module is available
if (Get-Module -ListAvailable -Name "MicrosoftTeams") {
Write-Verbose "MicrosoftTeams module already installed."
}
else {
Write-Verbose "Installing module MicrosoftTeams - https://learn.microsoft.com/en-us/powershell/module/teams/?view=teams-ps."
Install-Module MicrosoftTeams
}
Write-Verbose "Importing module MicrosoftTeams."
Import-Module MicrosoftTeams
And we connect with Microsoft Teams so we can install the app later:
Write-Verbose "Connecting to Microsoft Teams"
$user = "<<the account id>>"
Connect-MicrosoftTeams -AccountId $user
The problem here is that I'm always getting the prompt for device authentication:
Of course this would never work in a pipeline. How can I make this work? Can I use Token to connect with Teams?
You can publish an app using Teams App Submission API to enable it across organization level. Please refer to this documentation for more details.
There is an ability to install an app for a user using the Microsoft Graph, which might be a better approach. See https://learn.microsoft.com/en-us/graph/api/userteamwork-post-installedapps?view=graph-rest-1.0&tabs=http . You can also see the option to list apps, which might be useful to check IDs etc.: https://learn.microsoft.com/en-us/graph/api/userteamwork-list-installedapps?view=graph-rest-1.0&tabs=http

Update Windows security remotely using powershell scheduled task

I am trying to Install windows security patches on a remote machine using powershell remoting.
This is the function i am using to Update windows
<#
.SYNOPSIS
This functiion will automatically install all avaialable windows updates on a device and will automatically reboot if needed, after reboot, windows updates will continue to run until no more updates are available.
#>
function Install-WindowsUpdates
{
Install-Module -Name PSWindowsUpdate -RequiredVersion 2.1.0.1 -Force
Import-Module PSWindowsUpdate -Force
Get-WindowsUpdate -install -acceptall
}
When i run this function on a local host, the function is successful in installing windows security patches. I have the below script to do the same remotely:
param(
[Parameter(Mandatory = $true)]
[string] $IPaddress
)
try
{
$secpasswd = ConvertTo-SecureString "Pass#12345678" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("Admin02", $secpasswd)
#Create a Session.
$Session = New-PSSession -ComputerName $IPaddress -Credential $cred
cd C:\Users\Admin01\Documents
. .\Install-WindowsUpdates.ps1
Invoke-Command -Session $Session -ScriptBlock ${function:Install-WindowsUpdates}
return $true
}
catch
{
return $false
}
When i run this script i am getting the below error:
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
+ CategoryInfo : NotSpecified: (:) [Get-WindowsUpdate], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,PSWindowsUpdate.GetWindowsUpdate
+ PSComputerName : 10.0.0.7
I have setup both the loaclhost and remote machine for remoting and able to execute other scripts remotely. Also have enabled WMI on the remote machine.
What other settings i have to do?
Using Scheduled Task:
I am using the following script to start a scheduled task:
param(
[parameter(Mandatory = $true)]
[string]$IPaddress
)
$PSModulePath = $env:PSModulePath
$SplittedModulePath = $PSModulePath.Split(";")
$ModulePath = $SplittedModulePath[0]
$secpasswd = ConvertTo-SecureString "Pass#12345678" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("Admin02", $secpasswd)
#Create a Session. Replace host name with the host name of the remote machine.
$Session = New-PSSession -ComputerName $IPaddress -Credential $cred
$User= "Admin02"
$Action= New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "$env:ALLUSERSPROFILE\Install-WindowsUpdate.ps1"
$Trigger= New-ScheduledTaskTrigger -At 5:05am -Once
Invoke-Command -Session $Session -ScriptBlock { Register-ScheduledTask -TaskName "Install-Updates" -User $Using:User -Action $Using:Action -Trigger $Using:Trigger -RunLevel Highest –Force }
I have copied the below script on the target machine at the path $env:ALLUSERSPROFILE
<#
.SYNOPSIS
This functiion will automatically install all avaialable windows updates on a device and will automatically reboot if needed, after reboot, windows updates will continue to run until no more updates are available.
.PARAMETER computer
Use the Computer parameter to specify the Computer to remotely install windows updates on.
#>
Install-Module -Name PSWindowsUpdate -RequiredVersion 2.1.0.1 -Force
Import-Module PSWindowsUpdate -Force
Get-WindowsUpdate -install -acceptall
After i schedule the task nothing is happening.What i am doing wrong?
Yea, I fought this for weeks and finally have a good solution. The solution is actually built right into the PSWindowsUpdate module. The built in solution does use a windows Task, but it launches right away, and its actually helpful in tracking its completion progress, and it keeps the integration secure. The issue I have found is that PSWindowsUpdate has poor documentation. The following code worked for me:
Invoke-WUJob -ComputerName $svr -Script {ipmo PSWindowsUpdate; Get-WUInstall -AcceptAll -AutoReboot -Install | Out-File C:\PSWindowsUpdate.log } -Confirm:$false -Verbose -RunNow
There is a lot of scattered information on this topic, so please do your reading. PSWindowsUpdate is by far the best library for this job, and although its been a long process for me, I believe the above solution will work for everyone.
Please remember, the computer you are running the above scrip from needs to trust the computer you are trying to update, you can run this script to trust the computer:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value <ComputerName>
NOTE: Wildcards can be used in computer name
I also wanted to give you some information that greatly helped me:
Get-WindowsUpdate: This is the main cmdlet of the module. It lists, downloads, installs or hides a list of updates meeting predefined requisites and sets the rules of the restarts when installing the updates.
Remove-WindowsUpdate: Uninstalls an update
Add-WUServiceManage: Registers a new Windows Update API Service Manager
Get-WUHistory: Shows a list of installed updates
Get-WUSettings: Gets Windows Update client settings
Get-WUInstallerStatus: Gets Windows Update Installer Status, whether it is busy or not
Enable-WURemoting: Enables firewall rules for PSWindowsUpdate remoting
Invoke-WUJob: Invokes PSWindowsUpdate actions remotely
Like for all PowerShell cmdlets, different usage examples can be shown for each command typing Get-Help “command” -examples.
PSWindowsUpdate main parameters
As shown in the previous section, the PSWindowsUpdate module includes different predefined aliases to ease patching processes. However, main parameters for the Get-WindowsUpdate cmdlet will be listed and explained below:
Filtering updates:
AcceptAll: Downloads or installs all available updates
KBArticleID: Finds updates that contain a KBArticleID (or sets of KBArticleIDs)
UpdateID: Specifies updates with a specific UUID (or sets of UUIDs)
Category: Specifies updates that contain a specified category name, such as ‘Updates,’ ‘Security Updates’ or ‘Critical Updates’
Title: Finds updates that match part of title
Severity: Finds updates that match part of severity, such as ‘Important,’ ‘Critical’ or ‘Moderate’
UpdateType: Finds updates with a specific type, such as ‘Driver’ and ‘Software.’ Default value contains all updates
Actions and targets:
Download: downloads approved updates but does not install them
Install: installs approved updates
Hide: hides specified updates to prevent them to being installed
ScheduleJob: specifies date when job will start
SendReport: sends a report from the installation process
ComputerName: specifies target server or computer
Client restart behavior:
AutoReboot: automatically reboots system if required
IgnoreReboot: suppresses automatic restarts
ScheduleReboot: specifies the date when the system will be rebooted.
#How to avoid accidental installs#
Windows updates and patches improve the features and stability of the system. However, some updates can mess up your system and cause instability, especially automatic updates for legacy software such as graphic card drivers. To avoid automatic updates and accidental installs for such applications, you can pause Windows updates.
Alternatively, you can hide the specific updates for those features you don’t want to get updated. When you hide the updates, Windows can no longer download and install such updates. Before you can hide the update, you need to find out its details, including its knowledge base (KB) number and title. Type the cmdlet below to list all the available updates on your system:
Get-WUList
To hide a specific update using the KB number, use your mouse to copy that KB number. Next, type the command below:
Hide-WUUpdate -KBArticleID KB_Number
Highlight the “KB_Number” and click paste to replace that part with the actual KB number.
When prompted to confirm the action, type A, and hit the Enter key. If the command succeeds, the “Get-WUList” lists all the available updates, with hidden updates appearing with the symbol “H” under their status.
The KB number for the update may not be available for some updates. In this case, you can use the title to hide the update. To do this, list all the available updates via the cmdlet below:
Get-WUList
Next, use your mouse to copy the update title. Ensure it is distinct from other update titles. Now, type below command below to hide the update:
Hide-WUUpdate -Title “Update_Title”
Don’t forget to paste the actual update title in the “Update Title” section.
When prompted to confirm the action, type A, and hit the Enter key. If the command succeeds, the “Get-WUList” lists all the available updates. However, the status of hidden updates appears with the symbol “H” underneath them.
How to determine errors
It is of crucial importance to have as much information as possible about Windows Updates installation processes in order to be able to fix erroneous deployments. The Get-WindowsUpdate cmdlet and the rest of cmdlets available in the module, provide a very detailed log level when managing updates, including status, KB ID, Size or Title.
Centralizing all of the computer logs and analyzing them searching for errors, administrators will always be able to know the patch level of their Windows computers and servers.
The above passages came from this site!
This seems to be not possible by design:
Source 1
Source 2
Source 3
It is impossible for remotely connected users to download stuff from the internet it appears.
Speaking about windows update, you have many options like:
Connection using psexec tool then run wuauclt /detectnow /updatenow
If you are using windows 10 /server 2016 , the tools was replaced with USOClient.exe which is more effective.

Powershell: Uninstall application by UpgradeCode

When I upgrade / downgrade my application via a Powershell script, I want to first force the uninstallation of the currently installed version before running the new installer.
How can I do that with Powershell, using the UpgradeCode of the application?
Doing it by application name would be less robust.
Since you mention upgrade code, it must mean that you are talking about an MSI file (Windows Installer). As stated by others such an uninstall is normally performed auto-magically by a properly authored MSI package - it is referred to as a major upgrade - which is essentially an uninstall of the existing version of a product and then the install of the newest version.
The Upgrade Table of the MSI being installed will specify what existing packages on the box will be uninstalled before the new version is installed. In theory you can uninstall any number of existing installations. You can even uninstall a competitive product if you are mad as a hatter. Frankly, and astonishingly, I have never tried to uninstall multiple products during one major upgrade - it is rarely called for. In most cases you uninstall a single, existing product and then install your latest version.
You can modify the Upgrade table using a transform to change how the major upgrade behaves - in other words to make it start or stop uninstalling a specific pre-existing installation.
You can also enumerate all related products that share the same upgrade code by calling this MSI API function (COM - VBScript used as sample):
Set installer = CreateObject("WindowsInstaller.Installer")
' Enumerate all products related to "Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148"
' {AA783A14-A7A3-3D33-95F0-9A351D530011} is the upgrade code
Set upgrades = installer.RelatedProducts("{AA783A14-A7A3-3D33-95F0-9A351D530011}")
For Each u In upgrades
MsgBox u, vbOKOnly, "Product Code: "
Next
Then you can uninstall the products by passing the product code(s) to the msiexec.exe command line (see below for how to do this via MSI API COM automation instead):
msiexec.exe /x {11111111-1111-1111-1111-11111111111X} /L*V "C:\msilog.log" REBOOT=ReallySuppress
Quick Parameter Explanation (since I recommend this option):
/X = run uninstall sequence
/QN = run completely silently
/L*V "C:\msilog.log"= verbose logging at path specified
{11111111-1111-1111-1111-11111111111X} = product guid of app to uninstall
REBOOT=ReallySuppress = prevent reboot without warning (badly authored MSI packages)
If you don't want to uninstall via msiexec.exe, then you can find a myriad of ways to invoke an MSI uninstall here:
Uninstalling an MSI file from the command line without using msiexec.
And you can find the product code of an installed MSI in several different ways: How can I find the product GUID of an installed MSI setup?
UPDATE: I guess I forgot the obvious, you can uninstall directly via MSI API automation. In the script below we get all products sharing the same upgrade code and then uninstall them in sequence.
Note that when run silently you should run with admin rights since the UAC may be suppressed and then the uninstall will usually fail (permission denied). Because of this the below script runs the uninstall interactively - allowing UAC prompting and elevation.
And if it isn't obvious: running this script will uninstall Orca! I use this product as a sample because it is quick to install again (hints on finding the installer quick if you need to towards bottom here - search for "orca"):
BIG DISCLAIMER:
The COM method installer.ConfigureProduct does not accept any arguments that allow us to pass in REBOOT=ReallySuppress. This means that a (very) badly authored package which triggers the ScheduleReboot action (or uses some more obscure magic to cause a reboot) - may reboot the system without warning if you run the below script with admin rights and in silent mode.
There is a newer call ConfigureProductEx which is available as a Win32 function, but it is not exposed via the COM automation interface. If you platform invoke you can use that call - there is a C++ example in section 14 here: Uninstalling an MSI file from the command line without using msiexec. Or you can use the DTF feature from the WiX toolkit (see section 6 in the same link as the C++ example).
UPDATE July 2018:
Set installer = CreateObject("WindowsInstaller.Installer")
installer.InstallProduct "product.msi", "REMOVE=ALL REBOOT=ReallySuppress"
Set installer = Nothing
Perhaps the above snippet is the best uninstall approach? This should suppress any reboots. I don't have the time or the setup to test it right now (on a Linux box), but I wanted to add it before I forget.
Original uninstall script:
Const msiUILevelNone = 2
Const msiInstallStateAbsent = 2
Set installer = CreateObject("WindowsInstaller.Installer")
'installer.UILevel = msiUILevelNone ' Disabled to prevent silent uninstall. Now the UAC prompt will show
' Uninstall Orca, replace upgrade code with yours
Set products = installer.RelatedProducts("{CFF4D510-79B2-1CCD-0061-5741A0565A76}")
For Each product In products
' MsgBox "Product Code: " & product ' Show the product code found, if you want
' The following call when run silently with admin rights may reboot the system without warning!
' This is due to badly authored MSI packages - most packages will not trigger this problem.
installer.ConfigureProduct product, 0, msiInstallStateAbsent ' Uninstall product
' See text above for info on the newer ConfigureProductEx method.
Next
Set installer = Nothing
MsgBox "Finished" ' Just so we know the script ran if nothing found to uninstall
Some Links:
Is there an alternative to GUID when using msiexec to uninstall an application? (uninstall by product name)
How can I uninstall an application using PowerShell?
How can I use powershell to run through an installer?
WIX (remove all previous versions)
Wix upgrade goes into maintenance mode and never does upgrade (various ways to uninstall, by product code, by upgrade code, etc...)
Since the question specifically mentions powershell I'll just put this here too. There are other PS solutions around using WMI and/or Get-Package. This solution is based off of https://outnull.wordpress.com/2016/11/02/uninstalling-application-based-on-upgradecode/ but accepts various forms of upgrade code syntax, and it tries to avoid string manipulation when converting to/from the package/upgrade Guid and the registry representation.
$upgradecode = "{CFF4D510-79B2-1CCD-0061-5741A0565A76}"
$installer = Join-Path -Path $env:SystemRoot -ChildPath "system32\msiexec.exe" -Resolve
function Reverse-Nibbles {
param ( [byte[]] $bytes )
# reverse nibbles of each byte
for($i = 0; $i -lt $bytes.Length; $i++ )
{
$bytes[$i] = (($bytes[$i] -band 0x0F0F) -shl 4) -bor (($bytes[$i] -band 0xF0F0) -shr 4)
}
Write-Output -NoEnumerate $bytes
}
function GuidToRegString {
param ( [guid] $guid )
$bigendian = (Reverse-Nibbles $guid.ToByteArray())
return [System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary]::new($bigendian).ToString()
}
function RegStringToGuid {
param ( [string] $guid )
$littleendian = (Reverse-Nibbles ([System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary]::Parse($guid).Value))
return [guid]::new($littleendian)
}
$upcode = GuidToRegString ([guid]::Parse($upgradecode))
if (Test-Path -Path "HKLM:\Software\Classes\Installer\UpgradeCodes\$upcode") {
$products = RegStringToGuid (Get-Item -Path "HKLM:\Software\Classes\Installer\UpgradeCodes\$upcode").Property
foreach ($prod in $products) {
$pguid = [guid]::new($prod)
$p = $pguid.ToString("B")
if ((Test-Path -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$p") -or
(Test-Path -Path "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$p"))
{
$logfile = Join-Path -Path $PSScriptRoot -ChildPath uninstall-$($pguid.ToString("D")).log
$args = #( "/x", $p, "/l*v", """$logfile""", "/q", "COMPLETE_UNINSTALL=1", "REBOOT=REALLYSUPPRESS" )
Write-Host "Uninstalling $p"
$uninst = Start-Process -FilePath """$installer""" -ArgumentList $args -PassThru -Wait
Write-Host $uninst.ExitCode
}
}
}

cmdkey in PowerShell doesn't work when run as a logon script?

Trying is use cmdkey in a PowerShell logon script to store credentials in the credential manager. When the script is run from PowerShell ISE everything works, but when it's run as a logon script via Group Policy everything but cmdkey works. Cannot for the life of me figure out why cmdkey will work everywhere except when the script run on logon.
# Checks if CRM for Outlook is isntalled by checking the folder path
$installed = Test-Path "C:\Program Files (x86)\Microsoft Dynamics CRM"
# Checks if the CRM has already been configured using the CoreConfigured registry entry
$configured = Get-ItemProperty -Path HKCU:\software\Microsoft\MSCRMClient -Name "CoreConfigured"
# If CRM is installed and not configured, configure it, if CRM is not installed or installed and configured, exit
If ($installed -eq "True" -and $configured.CoreConfigured -ne 1) {
$message1 = New-object -ComObject Wscript.Shell
$message1.Popup("Preparing to configure Microsoft CRM for Outlook, please make sure Outlook is closed.",10,"Systems")
# Prompts user for email address and Password to configure CRM for Outlook
$c = Get-Credential -Message "To confgiure CRM, please enter your email address and password:"
# puts user credentials into Windows Credential Manager using required CRM URLs
cmdkey /generic:Microsoft_CRM_https://disco.crm.dynamics.com/ /user: $c.Username /pass: $c.Password | Out-Null
cmdkey /generic:Microsoft_CRM_https://disco.crm4.dynamics.com/ /user: $c.Username /pass: $c.Password | Out-Null
$message2 = New-Object -ComObject Wscript.Shell
$message2.Popup("Please wait, a notification will appear when the configuration is complete.",10,"Systems")
# Silenty runs the CRM configuration Wizard with custom XML file
$exe = "C:\Program Files (x86)\Microsoft Dynamics CRM\Client\ConfigWizard\Microsoft.Crm.Application.Outlook.ConfigWizard.exe"
&$exe -p /Q /i 'C:\Program Files (x86)\Microsoft Dynamics CRM\Default_Client_Config.xml' /xa /l 'c:\temp\crminstall.txt' | Out-Null
$message3 = New-Object -ComObject Wscript.Shell
$message3.Popup("Configuration complete! You may now open Outlook!",10,"Systems")
}
else {
exit
}
I imagine cmdkey is using Microsoft's Data Protection API (DPAPI) to encrypt credentials so only the current user can retrieve them. You can't use this API unless the user's session is loaded. When your script runs, it may be too early in the logon process for the security information the DPAPI needs is loaded. I'm not sure how logon scripts work, but try putting a delay in your logon script until you get a value back.
Here's the PowerShell code that encrypts with the DPAPI:
$scope = [Security.Cryptography.DataProtectionScope]::CurrentUser
$encryptedBytes = [Security.Cryptography.ProtectedData]::Protect( $plainBytes, $null, $scope )
$decryptedBytes = [Security.Cryptography.ProtectedData]::Unprotect( $encryptedBytes, $null, 0 )
Add a loop in your logn script that tries to encrypt/decrypt some random array of bytes until it succeeds.
I had the same issue: cmdkey was not working in Powershell when run as a User Logon Script.
In my case the issue was related to the user's group membership. The user was a member of the group "Power Users", but not a member of the group "Users" (or any other group).
According to this article from Microsoft, the group "Power Users" has "no default user rights", while the group "Users" has rights to "perform common tasks, such as running applications, using local and network printers".
The solution was to add my user(s) to the group "Users". This immediately solved the issue and allowed cmdkey to work in Powershell Logon Scripts.
I had this same problem with a PowerShell GPO logon script calling cmdkey.exe. The credentials populated into Credential Manager for Users, but Administrators the credentials did not show up. I found out that the credentials are saving in Credential Manager, but for the elevated user. If you run cmdkey /list in an elevated command prompt you will see the credentials there.