SCCM and Client 'Replace' - sccm

GOAL: Rename all AD Objects to new convention and move them to new OU's in a restructured AD hierarchy.
I have a PS script that utilizes the SCCM site module and the Active Directory module to do the following:
Get-CMCollectionMember
For each Member name, Remove-CMDevice
Move-ADObject of the same Member name
Rename-Computer of the same Member name
Reboot the computer
Run SCCM TriggerSchedules for DDR and Hardware Inventory
When I run the triggerschedules, the PSComputerName shows as the computer objects OLD name. Not the new one.
Everything else seems to work - the AD object is moved, then renamed. The 'new' SCCM Device Object shows up in SCCM (via Delta System Discovery - Interval 5 min).
The problem is that SCCM (the client, I suspect) is holding on to old object info.
My question is, short of just reinstalling the client...why is this happening? I am not renaming the object in SCCM - the first step is actually removing the devices from SCCM. They are then rediscovered via Delta system discovery.
When I run...
Invoke-WMIMethod -ComputerName WD001-WK100 -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule $schedule
...at the end of the process, PSComputername is the old name.
Any advice appreciated.

Reinstalling the SCCM Client is simple, and works. I am just running this on the end instead of running cycles, since they all run when the client is reinstalled, anyway. It also clears up my issue:
Install-CMClient -DeviceName $pc -AlwaysInstallClient $true -ForceReinstall $true
Thank you!

Related

Creating service with short Name and DisplayName breaks WMI for services

Lately I was having problem with WMI on one of the systems (win server 2019). Service list in Task Manager was empty and running Get-WmiObject Win32_Service from powershell was returning Generic failure. After fruitless hours of searching and trying to repair system I gave up and was ready to reinstall system. Then error was reproduced on another machine by accident and I was able to narrow down cause of the problem. After creating windows service with short name and short display name WMI brakes after system restart but only if that service is first (in alphanumeric order) on services list. To reproduce this effect you only need to run
sc create "A1" binpath="D:\foobar.exe" DisplayName="A1" start=disabled
binpath is irrelevant, service doesn't need to be started. DisplayName doesn't need to be identical to name. After that command you need to restart (before restart everything works). After that if you go to services list in task manager it will be empty (probably using WMI to query services list). Now you can run sc delete "A1" and reopen task manager. Everything is back to normal.
Problem was reproduced on Windows Server 2019 and Windows 10 (didn't tried on other versions).
Is this a known bug or what is happening here?
EDIT
I'm not asking about how to use sc. It's doesn't matter. I provided commands that someone can run to reproduce problem. You can create service with that parameters however you want.
You are using the sc command line arguments in the incorrect format.
From MSDN:
Optionvalue
Specifies the value for the parameter named by Optionname. See the Optionname reference for a list of supported values. When a string is to be input, the use of empty quotes means that an empty string is passed in. Note that there is a space between OptionValue and the equal sign.
The correct command should be:
sc create "A1" binpath= "D:\foobar.exe" DisplayName= "A1" start= disabled

What can I query to see if Windows is booted and done with updates?

My goal is to remotely check a group of computers (extensive list) not only to see if the server has rebooted (usually when it was last rebooting), but if Windows is fully up and running at the login screen, and it won't restart for further updates or still be installing updates.
I did find a service called AppReadiness, which stopped it until the server rebooted. I am concerned that if it is set to manual, it may not always start. Could somebody please confirm if this is a reliable service?
EDIT: As I'm writing this, I did find out that it was stopped until it says "Working on updates, 100% complete, Don't turn off your computer" but as the server hung on that message, the AppReadiness service started. Is there anything better to watch? I've read other answers on different questions say to check if C$ is available, but that is available sooner than AppReadiness is available.
The code that is being used to check the service:
$creds = Get-Credential -Message "Enter server credentials:" -UserName "SERVERNAME\Administrator"
Get-WmiObject Win32_Service -ComputerName "SERVERIPADDRESS" -Credential $creds | Where-Object {$_.Name -eq "AppReadiness"}
EDIT 2: Also, instead of monitoring services, I have also tried looking for processes like winlogon.exe and loginui.exe for guidance on the server's condition but I'm not receiving the results I'm looking to record. These processes show when the server is getting ready when I was hoping they would only show once the login GUI was visible.
EDIT 3:
This edit is for the answer by #Kelv.Gonzales who stated to check for the Windows Event Log "DHCPv4 client service is started" log entry. That doesn't work and is on par with other services and events that I monitored. It shows valid before the login screen.
My code was:
$creds = Get-Credential -Message "Enter server credentials:" -UserName "SERVERNAME\Administrator"
$server = "IPADDRESSOFSERVER"
while($true)
{
$event = Get-WmiObject Win32_NTLogEvent -ComputerName $server -Credential $creds -Filter "(logfile='System' AND eventcode = '50036')" | select -First 1
$event.ConvertToDateTime($event.TimeWritten)
Start-Sleep -Seconds 5
}
That one liner will just fire off once of course. Any reason why you are using WMI, instead of the built-in PowerShell cmdlet - Get-Service?
My suggestion is use an WMI Event watcher, using what you already have in place but target the service and any dependent services and have that event notify you when the state is running.
Use PowerShell to Monitor and Respond to Events on Your Server
This article is using PowerShell and VBScript to do this, but you can do this with all PowerShell.
You can have a temporary or permanent watcher.
PowerShell and Events: WMI Temporary Event Subscriptions
Those can get a bit deep, so, if they aren't for you, you can just use your one line in a Do Loop that stops after the service comes online.
Basic example:
$TargetHost = $env:COMPUTERNAME
do {
$TargetOperation = Get-WmiObject Win32_Service -ComputerName $TargetHost |
Where-Object {$_.Name -eq "AppReadiness"}
"Checking host $TargetHost for service/process $($TargetOperation.Name)"
Start-Sleep -Seconds 3
} until (($TargetOperation).State -eq 'Running')
"Validation of host $TargetHost for service/process $($TargetOperation.Name) complete"
# Results
Checking host WS70 for service/process AppReadiness
Checking host WS70 for service/process AppReadiness
Checking host WS70 for service/process AppReadiness
Validation of host WS70 for service/process AppReadiness complete
You can of course add as many services or processes as you'd like using operation logic.
All the above applies to almost whatever you'd like to watch. Services, process, file-folder.
Or just use this script in the loop.
Get Remote Logon Status - Powershell
This script will return the logon status of the local or a remote
machine. Return types include "Not logged on", "Locked", "Logged
on", and "Offline.
The most useful part of this is to check whether a computer is in the
locked state, although the other return types could also be useful.
This is a simple function, and can easily be included in a larger
script. The return types could be changed to numbers for the calling
script to more easily parse the return value.
Download: GetRemoteLogonStatus.ps1
Would finding 0 updates queued accomplish what you need then? This arcticle goes into detail on how to accomplish it.
To check if windows is ready to log in, can you query for the event log for 'DHCPv4 client service is started' - Event ID 50036 satisfy if windows is ready.
I spent a week searching for a solution for this issue. I wanted to share what is currently my best solution, hopefully it helps someone.
#kelv-gonzales pointed me in the right direction with his comment about the Windows Modules Installer and TrustedInstaller.
Breakdown of my solution
There exists a process called TiWorker.exe that is the Windows Modules Installer Worker process. This is the process responsible for actually installing the Windows Update. This process (from what I've observed) reliably runs throughout the duration of a Windows Update being installed. Once the update has been installed and a pending reboot is required, this process stops and goes away.
When you reboot the machine to satisfy the pending reboot, the TiWorker.exe process is one of the very first processes to start while the machine is coming back up. In some cases, depending on the nature of the update, will finish the installation of an update (that's the increasing percentage you see during boot-up) while the computer comes back up. Once the login screen is available, this process typically remains running four roughly 2 minutes (from what I've observed). After which, it stops and goes away. I found that waiting these few minutes was a small price to pay for reliably knowing when updates have finished processing.
My scripts logic
I was able to write a script that keys off of the existence of this service. For example, below is a high-level flow of my script.
Initiate the installation of Windows Updates.
Wait for updates to finishing installing and for a pending reboot.
Once a pending reboot exists, wait until TiWorker.exe is no longer running and then trigger a reboot.
While the machine is rebooting, repeatedly check the status of the machine during the reboot. While the machine is coming back up, TiWorker.exe will start back up to finish the update. Keep waiting until TiWorker.exe is no longer running (typically, the update will finish and the OS will wait at the lock screen for about 2 minutes before this process stops).
Code
I modified the code posted by #gabriel-graves to check for the TiWorker.exe process.
$creds = Get-Credential -Message "Enter server credentials:" -UserName "SERVERNAME\Administrator"
Get-WmiObject Win32_Process -ComputerName "SERVERIPADDRESS" -Credential $creds | Where-Object {$_.Name -eq "TiWorker.exe"}

View the active remote desktop connection on a given computer

I am looking for a tool to know if a given computer on the local network is being remotely accessed by a user or not and ideally I'd like to know who that user is. In my company, we share virtual machines and we keep have to ask members in the team if they use any remote computer. I'd like to have some kind of dashboard that can tell me what computer is being used, and what computer is free.
I am happy to use any kind of commercial solution that would require the install of services on each of the machines that need to be monitored or things like that.
The below is made easier if you're querying from a Windows client joined to the same domain as the system you are querying, and may require certain rights above and beyond a standard domain user. If you run into authentication/permission issues, that would be the first thing I'd check.
There is a tool available at least as far back as Windows XP called "qwinsta". Later versions of Windows have both qwinsta and "query session".
qwinsta /server:computer01
SESSIONNAME USERNAME ID STATE TYPE DEVICE
console 0 Conn wdcon
rdp-tcp 65536 Listen rdpwd
administrator 2 Disc rdpwd
That shows user "administrator" logged in but disconnected. Since in this example computer01 is a Windows Server 2003 system with the default "administration" RDP license, there's a second session listening for someone to connect.
Running the same command again after connecting to that previously disconnected session looks like this:
SESSIONNAME USERNAME ID STATE TYPE DEVICE
[unchanged output removed]
rdp-tcp#25 administrator 2 Active rdpwd
This is enough to answer "is someone currently active via RDP", and if you're using individual usernames, it should answer the "who" as well. If you're all using "testuser" or "administrator" or something, you'll probably want to know the answer to "from what client", and that is not given above.
The above gives a quick basic answer without needing additional tools. For more detailed information, you might look at the cassia library or PSTerminalServices (built on cassia). See some of the answers in this question for more detail.
My first thought on this was to use Sysinternals tools such as PsLoggedOn or LogonSessions. I then found reference to the previously-unknown-to-me qwinsta and rwinsta tools in this blog post from 2003.
You can use a PSModule named PSRdSessions, this module provide some simple funtions
sample of use
Get-RdSession -ComputerName Server01.domain.xyz # return [Cassia.Impl.TerminalServicesSession]
for return [hashtable]
Get-RdSession -ComputerName Server01.domain.xyz | Convert-RdSession # return
for return [pscustomobject]
Get-RdSession -ComputerName Server01.domain.xyz | Convert-RdSession | %{[pscustomobject]$_}

Map a network drive to be used by a service

Suppose some Windows service uses code that wants mapped network drives and no UNC paths. How can I make the drive mapping available to the service's session when the service is started? Logging in as the service user and creating a persistent mapping will not establish the mapping in the context of the actual service.
Use this at your own risk. (I have tested it on XP and Server 2008 x64 R2)
For this hack you will need SysinternalsSuite by Mark Russinovich:
Step one:
Open an elevated cmd.exe prompt (Run as administrator)
Step two:
Elevate again to root using PSExec.exe:
Navigate to the folder containing SysinternalsSuite and execute the following command
psexec -i -s cmd.exe
you are now inside of a prompt that is nt authority\system and you can prove this by typing whoami. The -i is needed because drive mappings need to interact with the user
Step Three:
Create the persistent mapped drive as the SYSTEM account with the following command
net use z: \\servername\sharedfolder /persistent:yes
It's that easy!
WARNING: You can only remove this mapping the same way you created it, from the SYSTEM account. If you need to remove it, follow steps 1 and 2 but change the command on step 3 to net use z: /delete.
NOTE: The newly created mapped drive will now appear for ALL users of this system but they will see it displayed as "Disconnected Network Drive (Z:)". Do not let the name fool you. It may claim to be disconnected but it will work for everyone. That's how you can tell this hack is not supported by M$.
I found a solution that is similar to the one with psexec but works without additional tools and survives a reboot.
Just add a sheduled task, insert "system" in the "run as" field and point the task to a batch file with the simple command
net use z: \servername\sharedfolder /persistent:yes
Then select "run at system startup" (or similar, I do not have an English version) and you are done.
You'll either need to modify the service, or wrap it inside a helper process: apart from session/drive access issues, persistent drive mappings are only restored on an interactive logon, which services typically don't perform.
The helper process approach can be pretty simple: just create a new service that maps the drive and starts the 'real' service. The only things that are not entirely trivial about this are:
The helper service will need to pass on all appropriate SCM commands (start/stop, etc.) to the real service. If the real service accepts custom SCM commands, remember to pass those on as well (I don't expect a service that considers UNC paths exotic to use such commands, though...)
Things may get a bit tricky credential-wise. If the real service runs under a normal user account, you can run the helper service under that account as well, and all should be OK as long as the account has appropriate access to the network share. If the real service will only work when run as LOCALSYSTEM or somesuch, things get more interesting, as it either won't be able to 'see' the network drive at all, or require some credential juggling to get things to work.
A better way would be to use a symbolic link using mklink.exe. You can just create a link in the file system that any app can use. See http://en.wikipedia.org/wiki/NTFS_symbolic_link.
There is a good answer here:
https://superuser.com/a/651015/299678
I.e. You can use a symbolic link, e.g.
mklink /D C:\myLink \\127.0.0.1\c$
You could us the 'net use' command:
var p = System.Diagnostics.Process.Start("net.exe", "use K: \\\\Server\\path");
var isCompleted = p.WaitForExit(5000);
If that does not work in a service, try the Winapi and PInvoke WNetAddConnection2
Edit: Obviously I misunderstood you - you can not change the sourcecode of the service, right? In that case I would follow the suggestion by mdb, but with a little twist: Create your own service (lets call it mapping service) that maps the drive and add this mapping service to the dependencies for the first (the actual working) service. That way the working service will not start before the mapping service has started (and mapped the drive).
ForcePush,
NOTE: The newly created mapped drive will now appear for ALL users of this system but they will see it displayed as "Disconnected Network Drive (Z:)". Do not let the name fool you. It may claim to be disconnected but it will work for everyone. That's how you can tell this hack is not supported by M$...
It all depends on the share permissions. If you have Everyone in the share permissions, this mapped drive will be accessible by other users. But if you have only some particular user whose credentials you used in your batch script and this batch script was added to the Startup scripts, only System account will have access to that share not even Administrator.
So if you use, for example, a scheduled ntbackuo job, System account must be used in 'Run as'.
If your service's 'Log on as: Local System account' it should work.
What I did, I didn't map any drive letter in my startup script, just used net use \\\server\share ... and used UNC path in my scheduled jobs. Added a logon script (or just add a batch file to the startup folder) with the mapping to the same share with some drive letter: net use Z: \\\... with the same credentials. Now the logged user can see and access that mapped drive. There are 2 connections to the same share. In this case the user doesn't see that annoying "Disconnected network drive ...". But if you really need access to that share by the drive letter not just UNC, map that share with the different drive letters, e.g. Y for System and Z for users.
Found a way to grant Windows Service access to Network Drive.
Take Windows Server 2012 with NFS Disk for example:
Step 1: Write a Batch File to Mount.
Write a batch file, ex: C:\mount_nfs.bat
echo %time% >> c:\mount_nfs_log.txt
net use Z: \\{your ip}\{netdisk folder}\ >> C:\mount_nfs_log.txt 2>&1
Step 2: Mount Disk as NT AUTHORITY/SYSTEM.
Open "Task Scheduler", create a new task:
Run as "SYSTEM", at "System Startup".
Create action: Run "C:\mount_nfs.bat".
After these two simple steps, my Windows ActiveMQ Service run under "Local System" priviledge, perform perfectly without login.
The reason why you are able to access the drive in when you normally run the executable from command prompt is that when u are executing it as normal exe you are running that application in the User account from which you have logged on . And that user has the privileges to access the network. But , when you install the executable as a service , by default if you see in the task manage it runs under 'SYSTEM' account . And you might be knowing that the 'SYSTEM' doesn't have rights to access network resources.
There can be two solutions to this problem.
To map the drive as persistent as already pointed above.
There is one more approach that can be followed. If you open the service manager by typing in the 'services.msc'you can go to your service and in the properties of your service there is a logOn tab where you can specify the account as any other account than 'System' you can either start service from your own logged on user account or through 'Network Service'. When you do this .. the service can access any network component and drive even if they are not persistent also.
To achieve this programmatically you can look into 'CreateService' function at
http://msdn.microsoft.com/en-us/library/ms682450(v=vs.85).aspx and can set the parameter 'lpServiceStartName ' to 'NT AUTHORITY\NetworkService'. This will start your service under 'Network Service' account and then you are done.
You can also try by making the service as interactive by specifying SERVICE_INTERACTIVE_PROCESS in the servicetype parameter flag of your CreateService() function but this will be limited only till XP as Vista and 7 donot support this feature.
Hope the solutions help you.. Let me know if this worked for you .
I find a very simple method: using command "New-SmbGlobalMapping" of powershell, which will mount drive globally:
$User = "usernmae"
$PWord = ConvertTo-SecureString -String "password" -AsPlainText -Force
$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
New-SmbGlobalMapping -RemotePath \\192.168.88.11\shares -Credential $creds -LocalPath S:
You wan't to either change the user that the Service runs under from "System" or find a sneaky way to run your mapping as System.
The funny thing is that this is possible by using the "at" command, simply schedule your drive mapping one minute into the future and it will be run under the System account making the drive visible to your service.
I can't comment yet (working on reputation) but created an account just to answer #Tech Jerk #spankmaster79 (nice name lol) and #NMC issues they reported in reply to the "I found a solution that is similar to the one with psexec but works without additional tools and survives a reboot." post #Larry had made.
The solution to this is to just browse to that folder from within the logged in account, ie:
\\servername\share
and let it prompt to login, and enter the same credentials you used for the UNC in psexec. After that it starts working. In my case, I think this is because the server with the service isn't a member of the same domain as the server I'm mapping to. I'm thinking if the UNC and the scheduled task both refer to the IP instead of hostname
\\123.456.789.012\share
it may avoid the problem altogether.
If I ever get enough rep points on here i'll add this as a reply instead.
Instead of relying on a persistent drive, you could set the script to map/unmap the drive each time you use it:
net use Q: \\share.domain.com\share
forfiles /p Q:\myfolder /s /m *.txt /d -0 /c "cmd /c del #path"
net use Q: /delete
This works for me.

How do I add Active Directory support to Windows PE?

I want to query Active Directory from Windows PE 2.0, which is not supported "out of the box." Microsoft seems to suggest that this is possible, but not with any tools they provide. What do you recommend?
There seem to be instructions here, and the author claims to query AD from WinPE.
http://www.clientarchitect.com/blog1.php/2008/06/18/windows-pe-2-0-ad-scripting-requirements
i recently needed to use a connection to AD from WinPE to retrieve some computer informations, i tested the above solution and other one with ADSI but not working for me in ADK 1709.
My final solution is using WMI on a DC with differed Credentials so can get all i need just by one line :)
(Get-WmiObject -Namespace 'root\directory\ldap' -Query "Select DS_info from DS_computer where DS_cn = $($AccountName)" -ComputerName $Domain -Credential $myADCred).$($Myattribute)
$AccountName : is the name of the computer i am searching in AD
$Domain : fqdn name that pointing to your DC ex:(xyz.youtdomain.com)
$MyADCred : is a credential object containing user and password with the necessary rights on AD
$myattribute : is the info i am searching from the computer in AD.
have a nice deployment :)
Yassine
Installing the ADSI package from deployvista.com solved the problem for me, but your mileage may vary.

Resources