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.
Related
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")
I have hit a problem I haven’t been able to solve despite trying quite hard.
Basically I have created a PowerShell script to alter\change values in the HKU hive for a specific user on a remote Windows 10 Amazon WorkSpace. The script loads the hive and makes the changes perfectly but I am getting an error when trying to unload the hive. I have tried various methods as suggested on different forums but to no avail. Here is the part of the script I’m having trouble with:
$WorkSpace = "blahComputerName"
$PSS = New-PSSession -ComputerName $WorkSpace
$UserAcc = "XXXXX"
$SID = (Get-ADUser -server MyDomain.com -Identity $UserAcc).SID.Value
Invoke-Command -Session $PSS -ArgumentList $SID, $UserAcc -ScriptBlock {
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
reg load "HKU\$($args[0])" "D:\Users\$($args[1])\NTUser.Dat"
Clear-ItemProperty -Path
"HKU:\$($args[0])\SOFTWARE\Microsoft\Office\Common\UserInfo" -Name
"UserInitials"
[gc]::collect()
Start-Sleep -Seconds 5
reg unload "HKU\$($args[0])"
Remove-PSDrive -Name HKU
}
Remove-PSSession -Id $PSS.Id
I have also read that using $SomeThing.Handle.Close() will close any open handles PowerShell might still have with the provider which might be causing the error but I can’t see how to use it in this context.
Here is the exact error:
ERROR: Access is denied.
+ CategoryInfo : NotSpecified: (ERROR: Access is denied.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ PSComputerName : blahComputerName
I have manually observed the remote registry hive being loaded and then apparently unloaded but this error worries me and would like to solve it. I have proved that its reg unload "HKU\$($args[0])" that is causing the error but cant find the correct solution.
The script runs with the required elevated privileges, so it’s not that. The remote WorkSpace is in a logged off state.
Any advice would be greatly appreciated.
Thank You
Though Garbage collection is nice, the problem stems from how this command is handled;
Clear-ItemProperty -Path
"HKU:\$($args[0])\SOFTWARE\Microsoft\Office\Common\UserInfo" -Name
"UserInitials"
I would recommend capturing it in a variable, like so;
$n = Clear-ItemProperty -Path "HKU:\$($args[0])\SOFTWARE\Microsoft\Office\Common\UserInfo" -Name "UserInitials"
Which should allow you to properly clean it up, like so;
$n.dispose()
$n.close()
Note the above is likely redundant (Dispose should close, and close should call dispose).
With the help of other examples I figured it out. Here's what needs to be done:
$tempHive = 'HKLM\TEMP_hive'
$ntUserFile = 'C:\Users\SOME_USER\NTUSER.DAT'
# Load hive
$startParams = #{
FilePath = 'reg.exe'
ArgumentList = "load `"$tempHive`" `"$ntUserFile`""
WindowStyle = 'Hidden'
Wait = $true
PassThru = $true
}
$process = Start-Process #startParams
if ($process.ExitCode) {
throw "Failed to load the temp hive '$tempHive' for '$ntUserFile': exit code $($process.ExitCode)"
}
# make registry hive drive mapping if needed
# New-Psdrive -name <blah> -PSProvider Registry -root <blih>
# close open handles for 'New-Item'
$result = New-Item -Path "HKLM:\TEMP_hive\newkey"
$result.Handle.Close()
# no need to close open handles from 'New-ItemProperty'
# $null = New-ItemProperty #newParams
# wait for garbage clean up
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
# if you did drive mapping with the mapped registry hive remove it before unload
# Remove-PSDrive <blah>
# unload the hive
$startParams = #{
FilePath = 'reg.exe'
ArgumentList = "unload `"$tempHive`""
WindowStyle = 'Hidden'
Wait = $true
PassThru = $true
}
$process = Start-Process #startParams
if ($process.ExitCode) {
throw "Failed to unload the temp hive '$tempHive' for '$ntUserFile': exit code $($process.ExitCode)"
}
I can run this script perfectly on my SharePoint server, and the user's profile picture gets updated:
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
$siteurl = "http://SHAREPOINTSITE/"
try {
$site = New-Object Microsoft.SharePoint.SPSite($siteurl)
} catch {
New-Item -ItemType File -Path C:\Users\admin\Desktop -Name ERROR1.txt -Value $_.Exception.Message -Force
}
try {
$context = [Microsoft.Office.Server.ServerContext]::GetContext($site)
} catch {
New-Item -ItemType File -Path C:\Users\admin\Desktop -Name ERROR2.txt -Value $_.Exception.Message -Force
}
#This gets the User Profile Manager which is what we want to get hold of the users
$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
$user = "DOMAIN\user.name"
#Put it in a loop for iterating for all users
if ($upm.UserExists($user)) {
try {
$profile = $upm.GetUserProfile($user)
$profile["PictureURL"].Value = "\\Sharepoint\C$\Users\admin\Desktop\1.jpg";
$profile.Commit();
} catch {
New-Item -ItemType File -Path C:\Users\admin\Desktop -Name ERROR3.txt -Value $_.Exception.Message -Force
}
}
New-Item -ItemType File -Path C:\Users\admin\Desktop -Name HELLO.txt -Force
$site.Dispose()
But when I run it from a remote PowerShell session, I am getting some weird errors:
ERROR1.txt
Exception calling ".ctor" with "1" argument(s): "The Web application at http://SHAREPOINTSITE/ could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application."
ERROR2.txt
Multiple ambiguous overloads found for "GetContext" and the argument count: "1".
I have checked all of the possibilities here, but still seeing this issue.
This is how I call the above script from the remote machine:
$spfarm = "DOMAIN\admin.username"
$spfarmpw = ConvertTo-SecureString "password123" -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $spfarm,$spfarmpw
$session = New-PSSession SharePoint -Authentication Default -Credential $cred
Invoke-Command -Session $session -FilePath "\\SharePoint\C$\Users\admin\Desktop\testremote.ps1"
I have tried calling this in a few different ways (e.g. hosting the script on my machine or hosting it on the SharePoint server, as well as using relative paths to call the script), but I always see these errors.
Can anyone please help me understand why this doesn't work when calling it from a remote PC? The script is clearly being called (HELLO.txt always gets created), but the SharePoint profile picture never gets updated - even though that script definitely should work.
Any help or guidance is much appreciated
nslookup
nslookup SHAREPOINTSITE
Output
Server: dc1.domain.co.uk
Address: xx.xx.x.xx
Name: sharepoint.domain.co.uk
Address: yy.yy.y.yy
Aliases: SHAREPOINTSITE.domain.co.uk
Where yy.yy.y.yy is the correct IP (it's the same address I see when executing ping SHAREPOINTSITE)
Try changing the Authentication method to CredSSP. This is required by the remote PowerShell so that it can pass the credentials on.
When attempting to access a network shared folder, DSC returns an "Access is denied" error, despite that I have provided a valid credential to it.
I'm using a DSC configuration, where a DSC "Script" resource is as follows:
Script myScriptResource {
GetScript = {return $true}
SetScript = {
$setupShare = '\\SomeNetworkSharesFolder\subFolder'
# This line produces valid results when run directly on node VM.
$build = Get-ChildItem "FileSystem::$setupShare" -Name | Sort-Object -Descending | Select-Object -First 1 | Out-String
Write-Host "Final Build: $build"
}
TestScript = {return $false} #Always run Set-Script block!
Credential = $ValidNetworkShareCredential
PsDscRunAsCredential = $ValidNetworkShareCredential
}
I receive an error:
VERBOSE: [MyNodeVM]: [[Script]myScriptResource] Performing the operation "Set-TargetResource" on target "Executing t
he SetScript with the user supplied credential".
Access is denied
+ CategoryInfo : PermissionDenied: (\\SomeNetworkSharesFolder\subFolder:) [], CimException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : myNodeVM
This might be due to the fact the LCM on the node VM is using a local SYSTEM user credential by default.
I attempted to change the user credential manually by navigating to the windows services manager (Hint: RUN then services.msc), and change the user credential in the logon tab of winRM service properties. Everytime I attempt to run the Windows Remote Management (WS-Managment) service, I receive and error:
Windows could not start the Windows Remote Management (WS-Management) service on Local Computer.
Error 1079: The account specified for this service is different from the account specified for other services running in the same process.
I don't know how to change the credential of LCM so that it can access the network shared folder upon the execution of Get-ChildItem.
Script myScriptResource {
GetScript = {return $true}
SetScript = {
$username ="someusername"
$secpasswd = ConvertTo-SecureString “somepassword” -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
$setupShare = '\\SomeNetworkSharesFolder\subFolder'
$psDriveArgs = #{ Name = ([guid]::NewGuid()); PSProvider = "FileSystem"; Root = $setupShare; Scope = "Private"; Credential = $mycreds }
new-psdrive #psDriveArgs -ErrorAction Stop
# This line produces valid results when run directly on node VM.
$build = Get-ChildItem "FileSystem::$setupShare" | Sort-Object -Descending | Select-Object -First 1 | Out-String
Write-Host "Final Build: $build"
}
TestScript = {return $false} #Always run Set-Script block!
}
There isn't an easy way to make it work with script resource because you need an ability to pass credentials to the script resource so that you can mount a drive and use it to copy/paste. If you want to copy files/directory from the share you can use 'File' resource. If you want to copy files/directory to the share you can use 'xFileUpload' resource from xPsDesiredStateConfiguration (https://gallery.technet.microsoft.com/xPSDesiredStateConfiguratio-417dc71d) Module. If you really need to use script resource to do this job, look into how xFileUpload resource is doing it.
I have been trying the following PowerShell script in several AD domain, but in one 2008 R2 domain it fails and I cannot find the reason for it:
PS D:\> Add-type -AssemblyName System.DirectoryServices.AccountManagement
PS D:\> $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
PS D:\> $Domain = $env:USERDOMAIN
PS D:\> $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext $ct,$Domain
PS D:\> $user = System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($pc, "SamAccountName", "testuser")
PS D:\> $groups = $user.GetAuthorizationGroups()
D:\> $groups
Normally the script gives a list of groups but for this domain it gives the following error message (after the list of groups):
An error occurred while enumerating through a collection: The specified directory service attribute or value does not exist.
CategoryInfo:InvalidOperation(System.Director...ment.Principal]:FindResultEnumerator`1) [], Runtime
Exception
FullyQualifiedErrorId : BadEnumeration
Could this have anything to do with AD privileges or permission?
I this could happen for a few possible reasons:
While the groups are iterating, it tries to resolve the SID to an Active Directory object that does not exist. I would check out your Active Directory to make sure that there is no missing or broken AD users/groups. (Something like this error: Microsoft Connect - Calling Principal GetAuthorizationGroups Error)
This could also be because of a Foreign Security principal that can't get resolved (Like this: Foreign Security Groups in Active Directory)
Some possible solutions:
Ignore the errors i.e. start off with $ErrorActionPreference = "SilentlyContinue"
Try something like this:
(Very rough code as a starting point)
$searchRoot = New-Object System.DirectoryServices.DirectoryEntry
$adSearcher = New-Object System.DirectoryServices.DirectorySearcher
$adSearcher.SearchRoot = $searchRoot
$adSearcher.Filter = "(samAccountName=UserName)"
$adSearcher.PropertiesToLoad.Add("memberOf")
$samResult = $adSearcher.FindOne()
if($samResult)
{
$adAccount = $samResult.GetDirectoryEntry()
$groupMembership = $adAccount.Properties["memberOf"]
$groupMembership | foreach {
Write-Host $_
}
}