|
Friday, March 31, 2006
PowerShell Remoting - Beta and future
Version 0.2.7.1
- New GUI client manager: Save/delete server information & connection option, generate connection script automatically, launch powershell remoting client directly.
- Add option to reject connection if user found invalid remote X509 certificate.
- Bug fix: Null login credential (press Cancel in CredUI window) cause server crash
- Bug fix: other minor bugs
Version 0.2.6.0
- Write Server Information & Error to EventLog (Source: PowerShellRemoting). Log file will no longer be used by newer version.
- SSL support using SSLStream.
- Get X509 certificate for server. For testing purpose, you can use makecert.exe (included in .NET framework SDK)
- Install X509 certificate at StoreLocation: LocalMachine, StoreName: My (personal).
- Grand "NetworkService" account read access to X509 certificate associated private key file.
- Set [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PowerShellRemoting\Parameters\ X509] to thumbprint of X509 Certificate.
There is pretty good walkthrough at John Howard's blog. - X509 Option
- DebugHost Option (Default 0: false)
- Bug fix: Write-Progress throw null object Exception.
Warning: SSL is for advanced user.
If you want to provide SSL support to server, you should
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PowerShellRemoting\Parameters]
"X509"="0"
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PowerShellRemoting\Parameters]
"DebugHost"=dword:00000000
Version 0.2.5.1
1. Support Ctrl+C and Ctrl+Break to cancel current pipeline (UDP datagram, So not 100% reliable)
2. Support Maximum Client per IP option (default 2)
3. Customized client filter policy (%Program Files%\PowerShell Remoting\user.xml, see sample files for format information)
Important: default installation only allow user in Administrators group login from localhost. So you have to have your own user.xml before you can login from another IP. If user.xml file parse error occorred when start service, default policy will be loaded. Check log file or EventLog for details of parse error.
4. $UserACL variable for current client filter policy
5. Client is installed as PSSnapin
6. New install/uninstall script for both server and client, new start-remotehost.ps1 script
7. CanThrowException and CanHandleCancelKey property of client (For developer)
8. Change Log file path to %Documents and Settings%\NetworkService\Local Settings\Application Data\PowerShellRemoting.log
9. Change Service Name to "PowerShellRemoting"
10. Service related Exception is also Logged to Eventlog (EventLog: Application, source: PowershellRemoting)
11. Other Bugs fixed
Version 0.1.1.7
1. Recompiled for new Windows PowerShell RC1 (Refresh version)
2. Using "Thread Pooling" method to schedule multiple Host threads. So Sever can potentially accept more connections. (Old version uses one thread per connection method).
3. Using a separate thread actively reclaim resources from broken connection and dead host.
4. Clean exit when stop service: Disconnect all clients and dispose all running hosts.
5. Gracefully disconnect client when server reach maximum client capacity.
6. Fix: Nested Prompt stack error when multiple clients connected.
7. Fix: Server unable to exit when connection closed unexpectedly by client.
8. Fix: "SetShouldExit" method re-throw "SocketException" Error
Version 0.1.0.318
1. Fix "All User" profile Path
1) "\Documents and settings\All users\Documents\PsConfiguration\profile.ps1"
2) "\Documents and settings\All users\Documents\PsConfiguration\PowerShellRemoting_profile.ps1"
Version 0.1.0.317
1. NestedPrompt (suspend host)
2. Multiple line input mode
3. Use local UI to get login credential
4. Save RawUI state on start, and Reset RawUI state on exit.
5. $CurrentUser Variable (WindowsIdentity Object represent current
login user)
6. Load user profile in following order
1) "\Documents and settings\All users\PsConfiguration\profile.ps1"
2) "\Documents and settings\All users\PsConfiguration\PowerShellRemoting_profile.ps1"
3) "My Documents\PsConfiguration\profile.ps1"
4) "My Documents\PsConfiguration\PowerShellRemoting_profile.ps1"
Version 0.1.0.311
1. Solve Server cause CPU overload problem
2. Solve Port or MaxClient change not take effect problem
3. Except for PSHostUserInterface.Prompt, all other UI/RawUI
API were connect to local UI/RawUI API
4. improved Client exception report
Version 0.1.0.301
1. Recompile for new Windows PowerShell RC1
2. Client class libary to build your own client
3. Console client use naive PowerShell.exe user interface
4. Support for all RawUI API
5. Bug fix for server
Version 0.1.0.128
1. Multiple connection (Maximum 10 connection)
2. New log file format
3. Hide some common exception on Client
4. Some bug fix
This software is distributed under BSD license. See license.txt for details.
I. What is "PowerShell Remoting"
PowerShell Remoting is a light-weighted server-client application which
provides secure remote access to Windows PowerShelll (codename Monad).
It contains two components:
Server: A Windows Service (Service Name "PowerShell Remoting") running
under NetworkService account. It will listen at certain TCP port, accept
income connection, authenticate client and provide PowerShell hosting
environment.
Client: A Class libary. It severs as a proxy between sever user interface
and client user interface. It will connect to server, provide client
credential for authentication, get user input and display results.
This software is distributed under BSD license. See license.txt for
details.
II. System requirement.
1. Microsoft .NET framework v2.0.50727 (Server & Client)
2. PowerShell RC1 or Higher (Server only)
3. Windows XP/2003 (For server); Windows 2000/XP/2003 (For client)
4. 256MB Memory, 1M hard drive space.
III. Features
1. Client authentication & protection
1) All communication between server and client is encrypted and signed.
Depend on server environment, authentication method could be NTLM or
Kerberos.
2) Multipul connection from client. (default Port 8080, Maximum 10 connection)
Can be changed by modify registry.
2. Support PSHostUserInterface & PSHostRawUserInterface
1) PSHostUserInterface will be passed to constructor of client
2) PSHostRawUserInterface is not mandatory but is supported
Note : Not supported at this version
1) Tab completion
2) start-transcript
Note. Known problems
1) Outputs of legacy program are not redirected to client
IV Installation and usage
# Server
1. Please use provided install.ps1 (install service) and uninstall.ps1
(uninstall service) to install/uninstall server component.
2. Default installation, server will listen to all available IP
(IPAddress.Any) listen at port 8080 and maximum client number is 10.
Those can be changed by modify registry
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PowerShell Remoting
\Parameters]
"Port"=dword:00001f90
"MaxClient"=dword:0000000a
3. Log file was "Hard Coded" to
C:\Documents and Settings\NetworkService\PowerShellRemoting.log
4. Default installed as Manual start service.
# Client
1. Client application do not need to be installed, just copy it to client
PC and execute "start-remotehost.ps1". (Some modification is needed)
2. argument:
start-remotehost
Where
(For example: 127.0.0.1- for localhost; 192.168.0.2, et, al.)
Where
(default 8080)
If you have any other suggestions, please drop a few lines in comment.
Have Fun
Tags: msh monad PowerShell
Monday, March 27, 2006
Monad Remoting - Windows Service
New feature:
1. Running as windows service under NetworkService account (Service Name "Monad Remoting").
2. Receiving customized NetworkCredential for logon. (Yes, I mean really logon) But only accept one connection at a time.
3. Impersonation as remote NetworkCredential. You can either login as an unprivileged user or an Administrator. Try my faverate id.msh to find out your current identity.
4. Log file was "Hard Coded" to
C:\Documents and Settings\NetworkService\MonadRemoting.log
5. Automatic install service (install.msh) and uninstall service (uninstall.msh). You 'd better install service using my install.msh because it creates required registry key.
6. Default installed as Manual start service. You can change it to Automatic in MMC service snapin. You have to start service before first connection.
Start-service "Monad Remoting"
7. Default listen at port 8080, can be changed by modify registry
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Monad Remoting\Port]
8: Default listen to all available IP (IPAddress.Any)
Have Fun
Wednesday, March 22, 2006
Monad Remoting - Now Can Read SecureString From Remote Client
Just upload a new version of "Monad Remoting". It can read SecureString from remote client console now.
SecureString will not be kept secret if you store its content in a normal string first. That is to say, we have to read it from console and store them directly as SecureString. But before sent them to remote server, we have to decrypt it to byte[ ]. NegotiateStream will encrypt (decrypted) byte[ ] before write to NetworkStream. At server side, we have to get the byte[ ] and restore it to a SecureString.
Although I tried to minimize exposure and clear my footprint behind me, there are still potential security problems. So use it at your own risk. I post the code here, in case someone want to take a close look at those steps I mentioned here.
doAt this point, you can now enjoy the get-credential, new-securestring cmdlets.
{
keyinfo = Console.ReadKey(true);
if ((keyinfo.Modifiers & ConsoleModifiers.Alt) != 0 || (keyinfo.Modifiers & ConsoleModifiers.Control) != 0) continue;
if (keyinfo.Key == ConsoleKey.Enter)
{
Console.WriteLine();
break;
}
if (password.Length == 512)
{
Console.Write("\r\nRead 512 (Maxium) Characters!");
break;
}
if (keyinfo.Key == ConsoleKey.Backspace)
{
password.RemoveAt(password.Length - 1);
Console.Write('\b');
Console.Write(' ');
Console.Write('\b');
continue;
}
password.AppendChar(keyinfo.KeyChar);
Console.Write('*');
}
while (keyinfo.Key != ConsoleKey.Enter);
if (password.Length > 0)
{
Plantext = GetByteArrayFromSecurString(password);
authStream.Write(Plantext, 0, Plantext.Length);
Array.Clear(Plantext, 0, Plantext.Length);
}
I really wish we could have a in-process su command, because the trick of
[System.Diagnostics.Process]::Start()will not work for remote client. Well, we have to expect that at next version of monad.
Have Fun.
Script to Resize Remote Client Console Window
MSH: Remote scripting host
Interstingly, if you run this script in msh.exe, you will probobly get some exception. But it works fine for my Monad Remoting tools.
Exception setting "WindowSize": "Window cannot be wider than the screen buffer.
Parameter name: value.Width Actual value was 85."
At D:\msh\script\resizewin.msh:7 char:18
Actually, This is a bug of my tools. I simply applied all RawUI operation directly to client console and but did not check screen buffer.
Have Fun!
Monday, March 20, 2006
Monad Remoting (updated version)
Feature:
# Automatic authentication
1) Client credential is automaticly provided to server for authentication.
2) All communication between server and client is entrypted and signed.
# Basic MshHostUserInterface.
1) Load User Profile at server when connected (new)
2) Evaluation for Prompt function (new)
3) Read and write from console
4) Colorized output
5) Prompt for undefined parameters (new)
6) Prompt for choice (new)
# Not supported at this version
1) Read Securestring
2) ReadKey
# known problems
1) Outputs of legacy program are not redirected to client
Have Fun.
Friday, March 17, 2006
Securely Extend Msh Host User Interface over Network
There is a followup post here.
Securely extend Msh Host User Interface over network using NegotiateStream.
If you follow my previous post, you will find out that I changed my strategy. There is no need to sent Mshobjects to remote client. We just need to implement a customized MshHostUserInterface which get input and write result to remote client. Monad is designed to be extended in this way, so it only took me a couple of days to get a usable solution. You can download testing binary at gotdotnet.
Server
Client
The underline idea is to implement all APIs in MshHostUserInterface and MshHostRawUserInterface. It was much easier than I originally thought. But I still had some problems with
public override Dictionaryin MshHostUserInterface andPrompt(string caption, string message, Collection descriptions) { }
public override int PromptForChoice(string caption, string message, Collectionchoices, int defaultChoice) { }
public override MshCredential PromptForCredential(string caption, string message, string userName, string targetName) { }
public override MshCredential PromptForCredential(string caption, string message, string userName, string targetName, MshCredentialTypes allowedCredentialTypes, MshCredentialUIOptions options) { }
public override SecureString ReadLineAsSecureString() { }
public override KeyInfo ReadKey(ReadKeyOptions options) { }in MshHostRawUserInterface.
public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill) { }
public override void SetBufferContents(Coordinates origin, BufferCell[,] contents) { }
public override void SetBufferContents(Rectangle rectangle, BufferCell fill) { }
That is to say: all sercurestring-related, credential-related, scroll console-related cmdlet are not working. But it is really fun to run some test on remote machine. Try out yourself by downloading the testing binary at gotdotnet.
Monad Rocks!
Have Fun!
Tuesday, March 14, 2006
Separation of Monad Engine and User Interface
The msh.exe is actully a console program hosting monad engine. In another word: monad engine does not worry about user interface, it is host environment's job. My Remote MSH server is not INTERACTIVE (For example: remote user will not be prompted to input credentials when invoking "get-credential" at server) because I use DefaultHost which does not Implement MshHostUserInterface.
OK, OK, it is to fast, let's start from Create a Runspace:
System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
public static Runspace CreateRunspace()So it acually create a Runspace using DefaultHost
{
Runspace runspace1;
using (IDisposable disposable1 = RunspaceFactory._tracer.TraceMethod())
{
runspace1 = RunspaceFactory.CreateRunspace(new DefaultHost(Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.CurrentUICulture));
}
return runspace1;
}
Microsoft.Management.Automation.Internal.DefaultHost is a implement of MshHost abstract class.
internal class DefaultHost : MshHostLet's take a look at System.Management.Automation.Host.MshHost
{
// Methods
static DefaultHost();
internal DefaultHost(CultureInfo currentCulture, CultureInfo currentUICulture);
public override void EnterNestedPrompt();
public override void ExitNestedPrompt();
public override void NotifyBeginApplication();
public override void NotifyEndApplication();
public override void SetShouldExit(int exitCode);
// Properties
public override CultureInfo CurrentCulture { get; }
public override CultureInfo CurrentUICulture { get; }
public override Guid InstanceId { get; }
public override string Name { get; }
public override MshHostUserInterface UI { get; }
public override Version Version { get; }
// Fields
private CultureInfo currentCulture;
private CultureInfo currentUICulture;
private Guid id;
[TraceSource("DefaultHost", "DefaultHost subclass of S.M.A.MshHost Tracer")]
private static MshTraceSource tracer;
private Version ver;
}
public abstract class MshHostMshHostUserInterface is the object which actully deals with user interface:
{
// Methods
protected MshHost();
public abstract void EnterNestedPrompt();
public abstract void ExitNestedPrompt();
public abstract void NotifyBeginApplication();
public abstract void NotifyEndApplication();
public abstract void SetShouldExit(int exitCode);
// Properties
public abstract CultureInfo CurrentCulture { get; }
public abstract CultureInfo CurrentUICulture { get; }
public abstract Guid InstanceId { get; }
public abstract string Name { get; }
public virtual MshObject PrivateData { get; }
public abstract MshHostUserInterface UI { get; }
public abstract Version Version { get; }
}
public abstract class MshHostUserInterfaceBut when we check the public property UI in DefaultHost:
{
// Methods
protected MshHostUserInterface();
public abstract Dictionary<string, MshObject> Prompt(string caption, string message, Collection<FieldDescription> descriptions);
public abstract int PromptForChoice(string caption, string message, Collection<ChoiceDescription> choices, int defaultChoice);
public abstract MshCredential PromptForCredential(string caption, string message, string userName, string targetName);
public abstract MshCredential PromptForCredential(string caption, string message, string userName, string targetName, MshCredentialTypes allowedCredentialTypes, MshCredentialUIOptions options);
public abstract string ReadLine();
public abstract SecureString ReadLineAsSecureString();
public abstract void Write(string value);
public abstract void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value);
public abstract void WriteDebugLine(string message);
public abstract void WriteErrorLine(string value);
public virtual void WriteLine();
public abstract void WriteLine(string value);
public virtual void WriteLine(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value);
public abstract void WriteProgress(long sourceId, ProgressRecord record);
public abstract void WriteVerboseLine(string message);
public abstract void WriteWarningLine(string message);
// Properties
public abstract MshHostRawUserInterface RawUI { get; }
}
public override MshHostUserInterface UISo, it is a null object.
{
get
{
MshHostUserInterface interface1;
using (IDisposable disposable1 = DefaultHost.tracer.TraceProperty())
{
interface1 = null;
}
return interface1;
}
}
If we want a REAL interactive remote shell, we have to implement our own MshHost and MshHostUserInterface (and maybe MshHostRawUserInterface). MshHostUserInterface will be responsible to write results to and get input from remote client. I bet this is the way Microsoft monad team will be using to provide remote access (maybe in version 2 of msh).
For me, it is too much work (and I would not compete with monad team). I really wish someone can show a example of implementation of MshHost and MshHostUserInterface. Maybe monad team would like to share their source code of msh.exe
Hehe, You know I am joking, right?
Added on Mar 15th 10:50am
I just find out that Microsoft Command Shell (MSH) Programmer's Guide are online now! It has exact information I needed.
Have Fun!
Monday, March 13, 2006
Securely Extend Monad Pipline over Network (2)
Usage:
1. Start MonadServiceHost.exe at Host Windows box with Monad installed (beta 3.1 for my testing):
MonadServiceHost.exe 8888Where "8888" is the port number you want server to listen. (Remember to allow accecc to local port 8888 in you firewall setting).
2. Start MSH.exe at client Windows box
MSH.exe3. Load MonadServiceClient.dll from within client MSH.exe
[System.Reflection.Assembly]::LoadFile("D:\MonadServiceClient.dll")where "D:\MonadServiceClient.dll" full path to MonadServiceClient.dll
4. Initialize a client object
$client = new-object MonadServiceClient.ClientLib (8888,"192.168.0.2")where "192.168.0.2" is the IP Address of Server, "8888" is port to connect .
5. Check out Method you can use
$client | get-member6. Connect client to remote server
$client.Connect()7. Using client to communicate with server
# Ping Server7. Disconnect client
$client.Ping()
# Invoke remote command
$client.Invoke("get-process")
$client.Invoke("set-location HKLM:")
# run remote script
$client.Invoke("D:\msh\id.msh")
# Redirect output to a file if return a lot of objects.
$client.Close()8. If something went wrong and you lost connection , just reconnect client
$client.Connect()
Have Fun!
Thursday, March 09, 2006
Securely Extend Monad Pipline over Network (1)
There are a lot of questions been asked in newsgroup about using Monad securely from remote computer. Ideally, we should have something like sshd in linux. But unlike traditional text based shell, Monad deal with .Net object using pipeline. Sshd did not have buildin functionality to work with .Net object. So it make sense to host monad in a ASP.NET application and send object over soap protocal.
But what if you don't want a CPU-intensive program or don't want to rely on IIS web server? Maybe you just want to access your desktop via a laptop on the same home network. I still remember in the "old time" I can use NetCat.exe binding a shell and gain remote access instantly. "Simple is beautiful", isn't it? That's why I write this tiny "toy" (File size: Server 24kb, client 20kb).
Design:
1. Server is a console program which hosts Monad Runspace, authenticates client using NegotiateStream and impersonates client using remote credential.
2. Client is class libary which sents out msh command to server.
3. Server gets command input, invoke monad pipline and get output objects.
4. Server serializes object and send them to client over secure tcp channel.
5. Client de-serializes object and emit them to client side interactive MSH for reuse.
Some thoughts:
1. Simple text-base control commands were used to control server and client. For example: Server sent a "SendObject" command to client; Client sent back an "OK" command and prepared to receive object; Server then sent serialized objects, Client de-serialized objects and sent back an "OK" command to finish this sequence.
2. Serialization and de-serialization of MshObject is the most difficult part. I still did not make it fully work. Serialization of every member in MshObject is not needed because some fields are session-dependent. We just need most important informations about the object so that we can operated those objects at server side.
3. Instead of creating a new instance of monad runspace for each invoke, remote session state should be maintained by server for each client. So client can use variable generated by previous command.
At this moment
1. Authentication and network are working fine.
2. Server can only accept one client at a time.(I will swith to asynchronous method later)
2. Client maintain connection status and can be controled by msh script.
2. It is barely usable as a interactive remote shell. for example, start remote service, kill remote process, run remote script (this is really cool).
3. Can NOT sent real object between server and client. Only important object information were transfered to client.
I will post binary and source code when it became more mature. See a screenshot of server console and client output below:
Host:
Client output:
>[System.Reflection.Assembly]::LoadFile("D:\msh\MonadServiceClient.dll")
GAC Version Location
--- ------- --------
False v2.0.50727 D:\msh\MonadServiceClient.dll
> $client = new-object MonadServiceClient.ClientLib (8080,"127.0.0.1")
> $client.Connect()
IsConnected : True
IsAuthenticated : True
IsMutuallyAuthenticated : False
IsEncrypted : True
IsSigned : True
RemoteIdentity : System.Security.Principal.GenericIdentity
Welcome : MSHForFun.MonadHostService Ready!
ConnectStartAt : 2006-3-9 15:33:54
ConnectEndAt : 0001-1-1 0:00:00
> $client.Invoke("set-location d:\msh")
OK: Null object in pipline
> $client.Invoke("get-location")
D:\msh
Drive:System.Management.Automation.DriveInfo Drive {get;}
Provider:System.Management.Automation.ProviderInfo Provider {get;}
ProviderPath:System.String ProviderPath {get;}
Path:System.String Path {get;}
> $client.Invoke("(get-process explorer).Id")
1644
> $client.ping()
Success
> $client.close()
IsConnected : False
IsAuthenticated : False
IsMutuallyAuthenticated : False
IsEncrypted : False
IsSigned : False
RemoteIdentity :
Welcome :
ConnectStartAt : 2006-3-9 15:38:46
ConnectEndAt : 2006-3-9 15:41:43
Have Fun!
Switch to BSD License
License is a sensitivie issue. Any comments on certain licence will cause a "war" in newsgroup. I am not a lawyer and I do not want to get into trouble either. I wrote all those codes just for fun and I do want to get more feed back for my project. So I take Lee Holmes' advice.
My MSHForFun.Security mshsnapin are now under BSD license.
Have Fun!
Wednesday, March 01, 2006
Release of MSHForFun.Security MshSnapin v0.1
Name : add-processowner
Definition : add-processowner [-ProcessArray] Process[] [-Verbose] [-Debug]
[-ErrorAction ActionPreference] [-ErrorVariable String] [-OutVa
riable String] [-OutBuffer Int32] [-WhatIf] [-Confirm]
Wrapper of OpenProcessToken Win32 API. It takes Process (output of get-process cmdlet) as input and adds process owner information (System.Security.Pricipal.WindowsIdentity) as NoteProperty.
Name : Get-Privilege
Definition : Get-Privilege [[-Identity] WindowsIdentity] [-Verbose] [-Debug]
[-ErrorAction ActionPreference] [-ErrorVariable String] [-OutV
ariable String] [-OutBuffer Int32] [-WhatIf] [-Confirm]
Wrapper of GetTokenInformation Win32 API. It takes System.Security.Pricipal.WindowsIdentity object as input and returns MSHForFun.Security.TokenPrivilegeCollection object. If used without parameter, it returns current process (msh.exe) token privileges.
Name : get-windowsidentity
Definition : get-windowsidentity [[-Credential] MshCredential] [-Verbose] [-
Debug] [-ErrorAction ActionPreference] [-ErrorVariable String]
[-OutVariable String] [-OutBuffer Int32] [-WhatIf] [-Confirm]
Wapper of LogonUser() Win32API. It takes MshCredential object as input and returns System.Security.Pricipal.WindowsIdentity object. If used without parameter, it returns System.Security.Pricipal.WindowsIdentity object represented current user.
Name : start-process
Definition : start-process [-FileName] String [-Credential MshCredential] [-
Arguments String] [-LoadUserProfile] [-UseShellExecute] [-Worki
ngDirectory String] [-CreateNoWindow] [-ErrorDialog] [-ErrorDia
logParentHandle IntPtr] [-RedirectStandardError] [-RedirectStan
dardInput] [-RedirectStandardOutput] [-StandardErrorEncoding En
coding] [-StandardOutputEncoding Encoding] [-Verb String] [-Win
dowStyle ProcessWindowStyle] [-Verbose] [-Debug] [-ErrorAction
ActionPreference] [-ErrorVariable String] [-OutVariable String]
[-OutBuffer Int32] [-WhatIf] [-Confirm]
Wrapper of System.Diagnostics.Process.Start() Methods. It takes MshCredential object as input and start a process using that credential. (Runas in MSH).
What's new?
- Wrap token handle into SafeTokenHandle, which is derived from Microsoft.Win32. SafeHandles. SafeHandleZeroOrMinusOneIsInvalid (try to prevent handle leakage and provides protection for handle recycling security attacks)
- Get-Privilege cmdlet
- Make sure all Exceptions were properly handled and using WriteWarning instead of WriteError, if we known errors will happen frequently (Add-Processowner)
- Rewrite C# code, correct errors and clean comments.
- System.Security.Pricipal.WindowsIdentity contains all important information inside a token except token privileges, so I took the challenge to write a Get-Privilege cmdlet.
- Mashalling memory block (struct TOKEN_PRIVILEGE) using C# is killing me. I will not do it again.
- MSHForFun.Security.TokenPrivilege contian 2 public property: Name and Status
- MSHForFun.Security.TokenPrivilegeCollection is derived from System.Collection.CollectionBase.
- Get-Privilege cmdlet is used for dump token privilege only.
>get-privilege (get-windowsidentity (get-credential))
Cmdlet get-credential at command pipeline position 1
Supply values for the following parameters:
Credential
User: Administrator
Password for user Administrator: *******
Name Status
---- ------
SeChangeNotifyPrivilege Enabled | Enabled By Default
SeSecurityPrivilege Enabled | Enabled By Default
SeBackupPrivilege Enabled | Enabled By Default
SeRestorePrivilege Enabled | Enabled By Default
SeSystemtimePrivilege Enabled | Enabled By Default
SeShutdownPrivilege Enabled | Enabled By Default
SeRemoteShutdownPrivilege Enabled | Enabled By Default
SeTakeOwnershipPrivilege Enabled | Enabled By Default
SeDebugPrivilege Enabled | Enabled By Default
SeSystemEnvironmentPrivilege Enabled | Enabled By Default
SeSystemProfilePrivilege Enabled | Enabled By Default
SeProfileSingleProcessPrivilege Enabled | Enabled By Default
SeIncreaseBasePriorityPrivilege Enabled | Enabled By Default
SeLoadDriverPrivilege Enabled | Enabled By Default
SeCreatePagefilePrivilege Enabled | Enabled By Default
SeIncreaseQuotaPrivilege Enabled | Enabled By Default
SeUndockPrivilege Enabled | Enabled By Default
SeManageVolumePrivilege Enabled | Enabled By Default
SeCreateGlobalPrivilege Enabled | Enabled By Default
SeImpersonatePrivilege Enabled | Enabled By Default
> get-privilege (get-process -Id 3768 | add-processowner).Processowner
Name Status
---- ------
SeChangeNotifyPrivilege Enabled | Enabled By Default
SeSecurityPrivilege Removed
SeBackupPrivilege Removed
SeRestorePrivilege Removed
SeSystemtimePrivilege Removed
SeShutdownPrivilege Removed
SeRemoteShutdownPrivilege Removed
SeTakeOwnershipPrivilege Removed
SeDebugPrivilege Enabled
SeSystemEnvironmentPrivilege Removed
SeSystemProfilePrivilege Removed
SeProfileSingleProcessPrivilege Removed
SeIncreaseBasePriorityPrivilege Removed
SeLoadDriverPrivilege Removed
SeCreatePagefilePrivilege Removed
SeIncreaseQuotaPrivilege Removed
SeUndockPrivilege Removed
SeManageVolumePrivilege Removed
SeCreateGlobalPrivilege Enabled | Enabled By Default
SeImpersonatePrivilege Enabled | Enabled By Default
>get-process | add-processowner
Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
71 3 1548 5304 38 0.80 864 acrotray
WARNING: Failed to openy process token (Access Denied): alg
105 5 1224 3604 35 2832 alg
....
(clipped)
>Start-process -Credential (get-credential) -FileName control.exe -Arguments timedate.cpl
Cmdlet get-credential at command pipeline position 1
Supply values for the following parameters:
Credential
User: Administrator
Password for user Administrator: *******
Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
0 0 64 60 1 0.00 2220 control
PS. some Non-MSH stuff:
Check out the "Brrreeeport" game on the Scobleizer blog.
Check out results on
1. Technorati
2. MSN Search
3. Google
4. Yahoo
Have fun!
[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]
Tags: msh monad PowerShell