Remotely delete multiple registry keys in a wildcard folder using powershell? - powershell

I am working on a script that will delete App-V keys stored in the registry. When a user opens an application, it creates a key within the following location:
HKLM\SOFTWARE\Microsoft\AppV\MAV\Configuration\Packages\**PackageID**\UserConfigEx\**SID**
The PackageID and the SID are unique each time and I want to be able to delete the SID subkey within each PackageID key.
The user will enter the SID and then I would like to use a wildcard (if possible) to navigate into each Package ID which is present.
So far I have the following:
#Take user input
$SID = Read-Host "Please enter users SID"
$computer = Read-Host "Please enter computer name"
#Test connection
Write-Host "Connecting to $computer"
if (Test-Connection -ComputerName $computer -Quiet -BufferSize 16 -Count 1) {
#Connect to registry and delete key
try
{
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘LocalMachine’, $computer)
$regKey = $reg.OpenSubKey(“HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\AppV\\MAV\\Configuration\\Packages\\*\\UserConfigEx\\$SID”,$true )
if ($regkey.GetValue(“$SID”))
{
$regKey.DeleteValue(“$SID”)
Write-Host
Write-Host "$SID key deleted successfully" -ForegroundColor Green
}
else
{
Write-Host
Write-Host "No keys with this SID exist." -ForegroundColor Red
}
} catch {
$ErrorMessage = $_.Exception.Message
Write-Host "Unable to connect to $computer. Error: $($ErrorMessage)." -ForegroundColor Red
}
} else
{
Write-Host "Unable to connect to $computer. Please ensure correct computer name / IP address has been entered correctly." -ForegroundColor Red
}
If I run this I receive:
You cannot call a method on a null-valued expression.
At line:51 char:9
+ if ($regkey.GetValue(“$SID”))
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
I am using some of the script which I received help with here to remotely connect to the machine.

The .NET registry API doesn't support wildcards (*) in key paths.
As a result, the $regKey.GetValue() failed, because $regKey = $reg.OpenSubKey(...) returned $null due to not finding a key, and calling a method on $null always results in the error message quoted in the question.
By contrast, PowerShell's registry provider, via the *-Item* cmdlets, does, but you need PowerShell remoting in order to use it remotely.
PowerShell remoting is enabled by default on Windows Server 2012 and above; on older OS versions you can enable it by running Enable-PSRemoting on the target machine(s) (requires PSv3+).
With PowerShell remoting enabled, you need to wrap your code in an Invoke-Command -ComputerName <name> { ... } call (to which you may have to pass credentials too).
If enabling PowerShell remoting is not an option, you must emulate wildcard-based matching via a nested loop based on per-element wildcard matching of the results from .GetSubkeyNames().
As an aside: you never need to escape \ as \\ in PowerShell strings; PowerShell uses ` as the escape character inside "...", so the only character you need to escape there is ` itself, as ``.
A PowerShell remoting-based solution:
Note that Invoke-Command -ComputerName ... must be called from an elevated session (Run As Administrator):
try {
Invoke-Command -ErrorAction Stop -ComputerName $computer {
# Define wildcard-based path.
$keyPath = "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppV\MAV\Configuration\Packages\*\UserConfigEx\$SID"
# See if it matches any keys.
if (Test-Path $keyPath) {
# Note: I'm assuming you want to remove the entire *key*.
# To only remove a key's *value*, use Remove-ItemProperty.
Remove-Item -Path $keyPath
} else {
Write-Warning "No keys with SID $SID exist."
}
}
} catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
# Note: Depending on the specifics of your Invoke-Command call, the reason may
# be permissions-related; when in doubt, examine $_
Write-Warning "Unable to connect to $computer. Please ensure correct computer name / IP address has been entered correctly:`n$_"
} catch {
# Other, unexpected failure.
Throw
}

Looks like an ascii vs unicode quotation mark issue:
You have:
$regkey.GetValue(“$SID”)
which should be replaced with:
$regkey.GetValue("$SID")

Related

How to Load Component Services/DCOM Config SnapIn

I have a PS script to do some DCOM configuration. It works fine as long as I have the Component Services/DCOM Config snapin loaded. I want to load that programmatically so I can do all of this as part of an install package. Does anyone know how to do it? I don't know the name of the snapin to add/import.
To load the snapin I run comexp.msc -32 and click Component Services, Computers, My Computer, DCOM Configuration.
Thanks
I faced a similar problem. I couldn't find a way of loading Component services on the DCOM Config spapIn. But I found a workaround to add the user the Default DCOM Launch and Activation permissions using this powershell script:
https://www.peppercrew.nl/index.php/2012/03/set-dcom-remote-access-via-powershell/
That way, you don't need to assign the user to that particular DCOM App.
Hope this help
This is the powershell script:
PARAM(
[string]$Principal = $(throw "`nMissing -Principal DOMAIN\Group"),
$Computers = $(throw "`nMissing -Computers ('server01','server02')"))
# USAGE:
# .\Set-RemotePermission-DCOM.ps1 -Principal "DOMAIN\" -Computers ('', '',...)
#
# EXAMPLE:
# .\Set-RemotePermission-DCOM.ps1 -Principal "DOMAIN\LG-Citrix-Admins" -Computers ('CTX_DC001', 'CTX_DC002')
#
# Inspired by Karl Mitschke's post:
# http://unlockpowershell.wordpress.com/2009/11/20/script-remote-dcom-wmi-access-for-a-domain-user/
#
# And inspired Brad Turner's post:
# http://social.technet.microsoft.com/Forums/en-US/ilm2/thread/5db2707c-87c9-4bb2-a0eb-912363e2814a/
function get-sid
{
PARAM ($DSIdentity)
$ID = new-object System.Security.Principal.NTAccount($DSIdentity)
return $ID.Translate( [System.Security.Principal.SecurityIdentifier] ).toString()
}
$sid = get-sid $Principal
#DefaultLaunchPermission - Local Launch, Remote Launch, Local Activation, Remote Activation
$DCOMSDDLDefaultLaunchPermission = "A;;CCDCLCSWRP;;;$sid"
#DefaultAccessPermision - Local Access, Remote Access
$DCOMSDDLDefaultAccessPermision = "A;;CCDCLC;;;$sid"
#PartialMatch
$DCOMSDDLPartialMatch = "A;;\w+;;;$sid"
foreach ($strcomputer in $computers)
{
write-host "`nWorking on $strcomputer with principal $Principal ($sid):"
# Get the respective binary values of the DCOM registry entries
$Reg = [WMIClass]"\\$strcomputer\root\default:StdRegProv"
$DCOMDefaultLaunchPermission = $Reg.GetBinaryValue(2147483650,"software\microsoft\ole","DefaultLaunchPermission").uValue
$DCOMDefaultAccessPermission = $Reg.GetBinaryValue(2147483650,"software\microsoft\ole","DefaultAccessPermission").uValue
# Convert the current permissions to SDDL
write-host "`tConverting current permissions to SDDL format..."
$converter = new-object system.management.ManagementClass Win32_SecurityDescriptorHelper
$CurrentDCOMSDDLDefaultLaunchPermission = $converter.BinarySDToSDDL($DCOMDefaultLaunchPermission)
$CurrentDCOMSDDLDefaultAccessPermission = $converter.BinarySDToSDDL($DCOMDefaultAccessPermission)
# Build the new permissions
if (($CurrentDCOMSDDLDefaultLaunchPermission.SDDL -match $DCOMSDDLPartialMatch) -and ($CurrentDCOMSDDLDefaultLaunchPermission.SDDL -notmatch $DCOMSDDLDefaultLaunchPermission))
{
$NewDCOMSDDLDefaultLaunchPermission = $CurrentDCOMSDDLDefaultLaunchPermission.SDDL -replace $DCOMSDDLPartialMatch, $DCOMSDDLDefaultLaunchPermission
}
else
{
$NewDCOMSDDLDefaultLaunchPermission = $CurrentDCOMSDDLDefaultLaunchPermission.SDDL + "(" + $DCOMSDDLDefaultLaunchPermission + ")"
}
if (($CurrentDCOMSDDLDefaultAccessPermission.SDDL -match $DCOMSDDLPartialMatch) -and ($CurrentDCOMSDDLDefaultAccessPermission.SDDL -notmatch $DCOMSDDLDefaultAccessPermision))
{
$NewDCOMSDDLDefaultAccessPermission = $CurrentDCOMSDDLDefaultAccessPermission.SDDL -replace $DCOMSDDLPartialMatch, $DCOMSDDLDefaultAccessPermision
}
else
{
$NewDCOMSDDLDefaultAccessPermission = $CurrentDCOMSDDLDefaultAccessPermission.SDDL + "(" + $DCOMSDDLDefaultAccessPermision + ")"
}
# Convert SDDL back to Binary
write-host "`tConverting SDDL back into binary form..."
$DCOMbinarySDDefaultLaunchPermission = $converter.SDDLToBinarySD($NewDCOMSDDLDefaultLaunchPermission)
$DCOMconvertedPermissionDefaultLaunchPermission = ,$DCOMbinarySDDefaultLaunchPermission.BinarySD
$DCOMbinarySDDefaultAccessPermission = $converter.SDDLToBinarySD($NewDCOMSDDLDefaultAccessPermission)
$DCOMconvertedPermissionsDefaultAccessPermission = ,$DCOMbinarySDDefaultAccessPermission.BinarySD
# Apply the changes
write-host "`tApplying changes..."
if ($CurrentDCOMSDDLDefaultLaunchPermission.SDDL -match $DCOMSDDLDefaultLaunchPermission)
{
write-host "`t`tCurrent DefaultLaunchPermission matches desired value."
}
else
{
$result = $Reg.SetBinaryValue(2147483650,"software\microsoft\ole","DefaultLaunchPermission", $DCOMbinarySDDefaultLaunchPermission.binarySD)
if($result.ReturnValue='0'){write-host " Applied DefaultLaunchPermission complete."}
}
if ($CurrentDCOMSDDLDefaultAccessPermission.SDDL -match $DCOMSDDLDefaultAccessPermision)
{
write-host "`t`tCurrent DefaultAccessPermission matches desired value."
}
else
{
$result = $Reg.SetBinaryValue(2147483650,"software\microsoft\ole","DefaultAccessPermission", $DCOMbinarySDDefaultAccessPermission.binarySD)
if($result.ReturnValue='0'){write-host " Applied DefaultAccessPermission complete."}
}
}
#----------------------------------------------------------------------------------------------------------
trap
{
$exMessage = $_.Exception.Message
if($exMessage.StartsWith("L:"))
{write-host "`n" $exMessage.substring(2) "`n" -foregroundcolor white -backgroundcolor darkblue}
else {write-host "`nError: " $exMessage "`n" -foregroundcolor white -backgroundcolor darkred}
Exit
}
#----------------------------------------------------------------------------------------------------------
I faced the same issue and, I believe, it's because there's no equivalent 64-bit registry entry so PowerShell doesn't see it. Launching mmc compexp.msc /32 and expanding DCOM Config seems to create the entry in the background.
The work-around is to manually add the 64-bit AppID yourself which is simply done by the following code,
$appGUID = 'YOUR_APPNAME_OR_GUID'
New-PSDrive -PSProvider Registry -Name HKCR -Root HKEY_CLASSES_ROOT
New-Item -Path HKCR:\AppID\$appGUID -Value $appGUID
#New-Item -Path HKCR:\Wow6432Node\AppID\$appGUID -Value $appGUID
Remove-PSDrive HKCR
I've left the 32-bit location in the above code too although that should already exist. Once you run the above then PowerShell should be able to see the COM component,
Get-WMIObject -query ('SELECT * FROM Win32_DCOMApplicationSetting WHERE AppID = "' + $appGUID + '"') -EnableAllPrivileges
Hope this helps someone as it was driving me bananas for hours!

PowerShell script fails to authenticate user when running Invoke-Command

I've recently created a little script that allows me to get the disk size and free space of 2 servers at each school site when I provide the script with the schools 4 digit site code.
First it pulls the information on the sites from a .csv file, and then uses that information to put together a string for the DC FQDN hostname, and the .10 server.
Then it requests the password for my elevated access account used to get the information on the disks.
I am having an issue where when the script creates the script block and then uses Invoke-Command and sends the script block to the servers, and provides back the PowerShell object with the information.
The error provided is as per below:
[{ServerName}] Connecting to remote server {ServerName} failed with the
following error message : WinRM cannot process the request. The following
error with errorcode 0x80090311 occurred while using Kerberos authentication:
There are currently no logon servers available to service the logon request.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does
not exist.
-The client and remote computers are in different domains and there is no trust
between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM
TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command:
winrm help config. For more information, see the about_Remote_Troubleshooting
Help topic.
+ CategoryInfo : OpenError: ({ServerName}:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : AuthenticationFailed,PSSessionStateBroken
Things I've tried:
Resetting my password
Altering the Authentication type to Basic
Getting others to try the same thing - some have the same issue, others do not
Other users on my workstations also have the same issue
I re-imaged my workstation and it worked for a bit, but then stopped again as it appeared to stop after the device installed software updates, so I'm in the middle of uninstalling those updates, however two of them won't allow me to uninstall, I assume they're forced installs by Microsoft and required to be installed (The uninstall button disappears when selected) - KB4019472 and KB4049065.
Device is running Windows 10 1607 v14393.1944, PowerShell v5.1.
There is a one-way trust between the domain I am in and the domains the DC1 and MS10 (.10) are in, the domains trust us, but we don't trust the domains.
The account I use is local admin on the device via a nested AD Group, across all domains.
I'm not very understanding of Kerberos, so any help would be amazing.
The script is below:
Note: I've had to remove some parts, so I've filled the area with what would be there (i.e. {String} where there would just be standard text, and {FQDNServerName} where there would be a FQDN server name written as text, or {Region} where I would have had the region written as text}).
$csvSchoolsLoc = "{FQDNServerName}\SharedReports$\SchoolsExport.csv"
$Schools = Import-Csv $csvSchoolsLoc -Delimiter "`t" -Header LocCode,SchoolName,SchoolAddress,SchoolPhoneNumber,SchoolFaxNumber,SchoolOfficerInCharge,DistrictCode,DistrictNumeric,RegionCode,RegionNumeric,LSD,WANLinkType,RouterName,RouterIP,RouterStatus,OneSchemaGraphUrl,OneSchemaSiteUrl,SCCMSiteID,SiteAdminNetwork,ProxyServerIP,PrimaryDcName,PrimaryDcIP,PrimaryDcOS,PrimaryDcVersion,PrimaryDcPatch,Style
#Gets the users credentials for their GBN ZZ account - this is used throughout the script for authentication
$username = "{Region}\zz-$env:USERNAME"
$mycreds = Get-Credential -UserName $username -Message "Enter your password for {region}\zz-$env:USERNAME"
Clear-Host
Write-Host "What is the schools 4 digit site code?" -ForegroundColor Magenta
$Global:SiteCode = Read-Host
Function Main {
Clear-Host
$SchoolName = $schools | Where-Object {$_.LocCode -eq $SiteCode} | ForEach-Object SchoolName
$Region = $schools | Where-Object {$_.LocCode -eq $SiteCode} | ForEach-Object RegionCode
Write-Host "Getting details for: " -ForegroundColor Gray -NoNewline; Write-Host "$SchoolName - $SiteCode - ($Region)"-ForegroundColor Yellow
$DC1 = "{String}$($Region)$($SiteCode)001.$region.{String}.{String}.{String}"
$MS10 = "{String}$($Region)$($SiteCode)010.$region.{String}.{String}.{String}"
if (Test-Connection -ComputerName $DC1 -Count 2 -Delay 1 -Quiet) {
$DC1Run = $true
} else {
$DC1Run = $false
}
if (Test-Connection -ComputerName $MS10 -Count 2 -Delay 1 -Quiet) {
$MS10Run = $true
} else {
$MS10Run = $false
}
$ScriptBlock = {
$DiskCTotal = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -Impersonation 3 | ForEach-Object {$_.size / 1GB}
$DiskCFree = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -Impersonation 3 | ForEach-Object {$_.freespace / 1GB}
$DiskZTotal = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='Z:'" -Impersonation 3 | ForEach-Object {$_.size / 1GB}
$DiskZFree = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='Z:'" -Impersonation 3 | ForEach-Object {$_.freespace / 1GB}
return #{
'ZFreeSpace' = $DiskZFree
'CFreeSpace' = $DiskCFree
'ZTotalSize' = $DiskZTotal
'CTotalSize' = $DiskCTotal
}
}
if (($DC1Run -eq $true) -and ($MS10Run -eq $true)) {
$ServerDC1 = Invoke-Command -ComputerName $DC1 -Credential $mycreds -ScriptBlock $ScriptBlock
$ServerMS10 = Invoke-Command -ComputerName $MS10 -Credential $mycreds -ScriptBlock $ScriptBlock
#Clear-Host
Write-Host -ForegroundColor Yellow "$SchoolName - $SiteCode - ($Region)"
Write-Host -ForegroundColor Cyan "Server $DC1 - Domain Controller"
Write-Host "$([math]::round($ServerDC1.CFreeSpace,2)) GB free on C Drive (Total Size $([math]::round($ServerDC1.CTotalSize,2)) GB)"
Write-Host "$([math]::round($ServerDC1.ZFreeSpace,2)) GB free on Z Drive (Total Size $([math]::round($ServerDC1.ZTotalSize,2)) GB)"
Write-Host ""
Write-Host -ForegroundColor Cyan "Server $MS10 - Distribution Point"
Write-Host "$([math]::round($ServerMS10.CFreeSpace,2)) GB free on C Drive (Total Size $([math]::round($ServerMS10.CTotalSize,2)) GB)"
Write-Host "$([math]::round($ServerMS10.ZFreeSpace,2)) GB free on Z Drive (Total Size $([math]::round($ServerMS10.ZTotalSize,2)) GB)"
} else {
#Clear-Host
Write-Host -ForegroundColor Yellow "$SchoolName - $SiteCode - ($Region)"
Write-Host -ForegroundColor Cyan "Server $DC1 - Domain Controller"
if ($DC1Run) {
Write-Host "DC1 connection status is running" -ForegroundColor Green
} else {
Write-Host "DC1 connection status is down" -ForegroundColor Red
}
Write-Host ""
Write-Host -ForegroundColor Cyan "Server $MS10 - Distribution Point"
if ($MS10Run) {
Write-Host "MS10 connection status is running" -ForegroundColor Green
} else {
Write-Host "MS10 connection status is down" -ForegroundColor Red
if ($DC1Run -eq $true) {
$RDP = Read-Host -Prompt "Would you like to RDP to $DC1 'Y'"
if ($RDP -eq "Y") {
Start-Process -FilePath "$env:windir\System32\mstsc.exe" -ArgumentList "/v:$DC1" -Wait -WindowStyle Maximized
}
}
}
}
Write-Host ""
Write-Host "What is the next schools 4 digit site code? -or- Press Enter to retry the above site again" -ForegroundColor Magenta
$Entry = Read-Host
if ($Entry -eq "") {
# Do nothing
} else {
$Global:SiteCode = $Entry
}
}
$x = 0
do {
Main
} until ($x -gt 0)
EDIT: The uninstall of the software updates did not fix the issue, so unless it's something to do with those 2 updates that I can't uninstall it doesn't appear to be Software Updates.
It turns out that the domains I am trying to reach were not in my TrustedHosts config for WinRM.
By using the following command, I was able to add the domains (of which I have numerous) to the TrustedHosts using the '*' wildcard.
NOTE: I have replaced part of the domain with {String} where it would normally have part of the domain name for confidentiality reasons.
winrm set winrm/config/client #{TrustedHosts="<local>,*.{string}.edu.au"}

Moving and renaming AppFabric configuration database

Recently we did a move and a rename of an AppFabric configuration database.
The rename was from default name "AppFabricConfigurationDatabase" to "AppFabricPreOrdersConfiguration"
DistirbutedCacheService.exe.config was changed with the new database and server name
<clusterConfig provider="System.Data.SqlClient" connectionString="Data Source=NEWSERVER;Initial Catalog=AppFabricPreOrdersConfiguration;Integrated Security=True" />
and the service starts succesfully.
But from this point on the "caching administration powershell" does not start anymore because when use-cachecluster is called it still tries to connect to the old server / database.
Test connection failed for ConnectionString Data Source=OLDSERVER;Initial Catalog
=AppFabricCacheConfigurationDatabase;
Use-CacheCluster : ErrorCode:SubStatus:Invalid provider and c
onnection string read.
Where does powershell read those values from? Apparently not from the config file of the service but where then?
Since I can't stop the cluster I've tried to see if the connection string would be changed without restarting and basically just calling Remove-CacheAdmin and Add-CacheAdmin....it worked!
Of course the script would have to be run on each host so not good for large setups but a restart is not really needed apparently
param ([string] $provider, [string] $newConnectionString)
function Main {
if ( (! $provider) -or (! $newConnectionString))
{
Write-Host "Usage: ChangeConnString.ps1 <provider> <newConnectionString>"
exit(1)
}
Import-Module "DistributedCacheAdministration"
Import-Module "DistributedCacheConfiguration"
[Reflection.Assembly]::LoadWithPartialName('Microsoft.ApplicationServer.Caching.Management') | Out-Null
[Reflection.Assembly]::LoadWithPartialName('System.Management.Automation') | Out-Null
[Reflection.Assembly]::LoadWithPartialName('System.Management.Automation.Runspaces') | Out-Null
Remove-CacheAdmin
Add-CacheAdmin -Provider $provider -ConnectionString $newConnectionString
}
The scripts provided by the other users did not work for me. I encountered exceptions. I was able to work around this issue by editing the registry on each host and restarting the service.
The connection string is stored here: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppFabric\V1.0\Configuration
The value is named "ConnectionString"
Under the user hive, there's another instance of the connection string. I don't know if you need to change this or not, but I did. HKEY_CURRENT_USER\Software\Microsoft\AppFabric\V1.0\Temp
That worked for me. Don't forget you also need to edit the ClusterConfig ConnectionString in DistributedCacheService.exe.config under C:\Program Files\AppFabric 1.1 for Windows Server
You need to call Remove-CacheAdmin and then Add-CacheAdmin to change the cache admin connection on each admin host
This Microsoft Powershell script - (.EXE download, script reproduced below) - changes the connection string on all hosts in a cluster.
param ([string] $provider, [string] $newConnectionString)
function Main {
if ( (! $provider) -or (! $newConnectionString))
{
Write-Host "Usage: ChangeConnString.ps1 <provider> <newConnectionString>"
exit(1)
}
Import-Module "DistributedCacheAdministration"
Import-Module "DistributedCacheConfiguration"
Use-CacheCluster
Write-Host "Stop the cache cluster if it is running"
$clusterRunnig=$true
&{
Stop-CacheCluster -EA Stop
}
trap [DataCacheException] {
#'Error Category {0}, Error Type {1}, ID: {2}, Message: {3} {4}' -f $_.CategoryInfo.Category, $_.Exception.GetType().FullName, $_.FullyQualifiedErrorID, $_.Exception.Message, $_.Exception.ErrorCode;
#12008: ErrorCode<ERRCAdmin008>:SubStatus<ES0001>:No hosts running in cluster
if ($_.Exception.ErrorCode -eq 12008)
{
write-host "Cluster is not running"
$clusterRunnig=$false
continue
}
}
[Reflection.Assembly]::LoadWithPartialName('Microsoft.ApplicationServer.Caching.Management') | Out-Null
[Reflection.Assembly]::LoadWithPartialName('System.Management.Automation') | Out-Null
[Reflection.Assembly]::LoadWithPartialName('System.Management.Automation.Runspaces') | Out-Null
SetCacheConnectionString $provider $newConnectionString
Write-Host "Connection string is altered on all the cache hosts. Now changing the connection string for cache admin"
Remove-CacheAdmin
Add-CacheAdmin -Provider $provider -ConnectionString $newConnectionString
if ($clusterRunnig -eq $true)
{
Write-Host "Starting the cache cluster..."
Start-CacheCluster
}
}
function SetCacheConnectionString {
param ([string] $provider, [string] $newConnectionString)
Write-Host "Parameters: " $provider " " $newConnectionString
$powerShell = [System.Management.Automation.PowerShell]::Create()
# Import the admin cmdlets module
$powerShell.AddCommand("Import-Module", $true);
$powerShell.AddParameter("Name", "DistributedCacheAdministration")
# Call the Invoke method to run the commands
$powerShell.Invoke();
$powerShell.Commands.AddCommand("Use-CacheCluster")
$powerShell.Commands.AddCommand("Get-CacheHost")
$commandResults = $powerShell.Invoke()
$powerShell.Dispose()
Write-Host "Number of hosts in the cluster " $commandResults.Count
foreach ($cacheHost in $commandResults)
{
Write-Host "Configuring the host " $cacheHost.HostName
Invoke-Command -ComputerName $cacheHost.HostName -ScriptBlock {param ($provider, $newConnectionString) Import-Module DistributedCacheConfiguration;Remove-CacheHost;Add-CacheHost -Provider $provider -ConnectionString $newConnectionString -Account 'NT Authority\NETWORK SERVICE'} -ArgumentList $provider, $newConnectionString
}
}
#
# Entry
#
Main

new-item Host-Instance - BizTalk Powershell Extensions

I'm trying to use the Powershell Extensions to BizTalk 2010 to add a Host-Instance (the host already exists).
Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions #NOTE: Must be in 32-bit version of Powershellto use this SnapIn
#get-PsSnapIn -registered ### list registered Snap-In's
$HostName = "TestNewHost"
$HostType = 1 # 1 = InProcess
$myNTHostGroupName = "BIZTALKDEV\Domain Users"
$AuthTrusted = $false
$domainName = "BizTalkDev"
$serverName = "BizTalkDev"
$defaultAdminUser = "Administrator"
$hostCredentials = $Host.ui.PromptForCredential("Logon Credentials","This account must have SQL Server permissions.", $domainName + "\" + $defaultAdminUser, "");
[String]$hostCredentialsPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($hostCredentials.Password));
#cd "Biztalk:\Platform Settings\Hosts"
#New-Item $HostName -HostType:$HostType -NtGroupName:$NTGroupName -AuthTrusted:$AuthTruste
#New-Item -path $hostName -HostType:$HostType -NtGroupName:$NTGroupName -AuthTrusted:$AuthTrusted
cd "BizTalk:\Platform Settings\Host Instances"
dir
Write-Host "Try to add New HostInstance=$hostName"
New-Item $hostName -HostName $hostName -Credentials $hostCredentials -RunningServer $serverName
dir
When I supply a valid domain user/password in the credentials, I get this error:
New-Item : Instance of the WMI class is not found.
No instance was found with the specified key. This could be the result of the instance being deleted by another BizTalk Admin session.At E:\CreateHost_PSSnapIn.ps1:27
char:1
If I leave off the -Credentials argument. It prompts me on that new-item for user/pass, and same error occurs. If I provide a totally bogus userid/pass, I still get the same error.
I found this issue. I had the wrong value for $servername, should have been "BizTalk2010Dev". I didn't catch that domain name and server name were different (this is a VM that a co-worker created).
So in summary, the error, while very ambiguous, was referring to the existing HostName being missing. All Host-Instances must be associated with an existing Host.

Check if a Registry Path Exists in Remote Machine

I have used Power Shell to check if a path exists using this command . powershell test-path "HKCU:\Software\Microsoft\Windows" now how can the same be extended to remote machine. What is the syntax if i want to test a registry path in Remote machine, i tried powershell test-path "\\machinename\HKCU:\Software\Microsoft\Windows" and its not working. Suggest some way to test it.
You can access it as outlined here: http://powershell.com/cs/blogs/tips/archive/2011/02/15/accessing-registry-remote.aspx
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', 'server123')
$key = $reg.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall')
$key.GetSubKeyNames() | ForEach-Object {
$subkey = $key.OpenSubKey($_)
$i = #{}
$i.Name = $subkey.GetValue('DisplayName')
$i.Version = $subkey.GetValue('DisplayVersion')
New-Object PSObject -Property $i
$subkey.Close()
}
$key.Close()
$reg.Close()
An alternative is to enable PSRemoting and use invoke-command on the remote machine and effectively run the same command as what you would run on the local box.
You cannot connect to the current user hive of a remote computer. Here's an example of using the Remote Regitry module to check if a remote key exists in the hklm hive of a remote server. The module can be found on codeplex: psremoteregistry.codeplex.con
Test-RegKey -ComputerName server1 -Key software\microsoft\winows -Hive LocalNachine
This site helped me. The code basically checks for one key and then checks for another one if the first one does not exist. It also verifies that the subkey exists before trying to read a value from it. If neither exist a try / catch can help deal with that.
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computerName)
$regkey = $reg.OpenSubkey("SOFTWARE\\Symantec\\Symantec Endpoint Protection\\AV\\Storages\\Filesystem\\RealTimeScan")
if(-not $regkey) {
$regkey = $reg.OpenSubkey("SOFTWARE\\Wow6432Node\\Symantec\\Symantec Endpoint Protection\\AV\\Storages\\Filesystem\\RealTimeScan")
}
$autoProtectStatus = ""
$null = ""
if ($regkey.GetValue("OnOff", $null) -ne $null) {
$autoProtectStatus = $regkey.GetValue("OnOff")
}
if ($autoProtectStatus -eq 1) {
$autoProtectStatus = "Protection On"
} elseif ($autoProtectStatus -eq 0) {
$autoProtectStatus = "Protection Off"
} else {
$autoProtectStatus = "Unknown State"
}
So much of the Q&A is 3 years old or older. I suspect the newer versions of Powershell must have cleaned up a lot of this. Having said that, there is still not a direct command to check the registry on a remote computer (to the best of my knowledge). This works - it checks if .NET 4.6.2 is installed (is it simpler than the other answers though?)
invoke-command -computername <NetBiosName> -scriptblock {test-path -Path
"HKLM:\Software\Microsoft\.NetFramework\v4.0.30319\SKUs\.NetFramework,
Version=v4.6.2"}
You can also put the scriptblock content into a *.ps1 file (everything inside the {} and then invoke it with: Invoke-Command -ComputerName NetBiosName -FilePath "FQLP"