我正在尝试检查Powerhell脚本是否以管理员身份运行。
在网上搜索后,我得到了一些可以正常工作的示例代码。
为了获得WindowsPrincipal
对象,我找到了以下两个示例代码。
第一:
New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
第二:
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
第二个让我感到困惑。
根据this page,我知道[ ]
是强制转换运算符。
根据{{3}},PowerShell是建立在.NET Framework之上的。我认为这意味着可以将上述两个PowerShell脚本转换为C#。
所以我尝试一下。
当我将第一个PowerShell脚本转换为C#时。可以正常工作,如下所示。
## First PowerShell script
New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
// C#
var wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
但是当我尝试将第二个PowerShell脚本转换为C#时。我得到编译错误。 IDE告诉我WindowsIdentity
无法转换为WindowsPrincipal
。
## Second PowerShell script
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
// both C# code below cause compile error
var wp = System.Security.Principal.WindowsIdentity.GetCurrent() as System.Security.Principal.WindowsPrincipal;
var wp2 = (System.Security.Principal.WindowsPrincipal)System.Security.Principal.WindowsIdentity.GetCurrent();
就像我在C#上尝试过的那样,System.Security.Principal.WindowsIdentity
类型不能直接转换为System.Security.Principal.WindowsPrincipal
类型。但是为什么第二个PowerShell脚本可用?
还是第二个PowerShell脚本中的[ ]
运算符不是类型转换运算符?
也许这个运算符不仅仅可以转换对象类型?
第一个PowerShell脚本和第二个PowerShell脚本有什么区别?
我还想念其他东西吗?
答案 0 :(得分:3)
TLDR:PowerShell可以执行 Magic 。 C#不能做魔术。
PowerShell可以同时处理电锯,保龄球和球。
如果C#是提前定义的,则C#只能处理它们。尝试在杂耍例程中添加新的电锯会导致杂耍者(编译器)抱怨。
问题在于函数,对象类型以及如何转换对象类型之间的差异。
System.Security.Principal
是基础.NET库。该库可由C#和PowerShell使用。
WindowsIdentity.GetCurrent()
是库中的函数。
WindowsPrincipal
是一种对象类型,例如例如string
或int
。
调用WindowsIdentity.GetCurrent()
返回一个WindowsIdentity
对象,然后可以在代码中使用它。
由于WindowsIdentity
不一定是您要使用的对象类型,因此我们想使用WindowsPrincipal
对象。不幸的是,我们无法直接从WindowsIdentity
投射到WindowsPrincipal
对象。我们必须使用WindowsPrincipal
构造函数。
在PowerShell中,您可以通过New-Object
cmdlet或首次使用变量来创建新对象。这样做的方便是因为PowerShell是脚本语言,其中使用了变量,例如$a = 1
隐式创建一个新变量。例如
PS C:\> Get-Variable test
Get-Variable : Cannot find a variable with the name 'test'.
At line:1 char:1
+ Get-Variable test
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (test:String) [Get-Variable], ItemNotFoundException
+ FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand
PS C:\> $test = 1
PS C:\> Get-Variable test
Name Value
---- -----
test 1
使用New-Object
示例:
New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
这是正确的方法。您正在创建WindowsPrincipal
类型的新对象,并将Windows身份传递给构造函数。
第二种方法:
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
是“错误的”,因为它使用了强制类型转换,并且前面我们说过我们不能直接从WindowsIdentity
强制转换为WindowsPrincipal
对象。那么这是如何工作的呢?好吧,我之前说过,PowerShell可以发挥魔力,好一会儿我会讲到。首先,让我们看看正确的C#代码:
在C#中调用.NET Framework特定功能的语法与PowerShell确实有所不同。而导致出现特定编译错误的原因是,因为我们正在尝试投射对象,而这是我们无法做到的。
示例:
using System.Security.Principal;
var wp = WindowsIdentity.GetCurrent() as WindowsPrincipal; // compile error
编译器将其翻译为:
WindowsIdentity.GetCurrent()
运行功能GetCurrent()
as WindowsPrincipal;
期望返回类型为WindowsPrincipal
<-编译时错误。编译错误是因为函数没有返回类型WindowsPrincipal
,而是返回了类型WindowsIdentity
。
第二个示例也是一个变体,因为它不能直接强制转换对象,因此无法使用。例如
using System.Security.Principal;
var wp = (WindowsPrincipal) WindowsIdentity.GetCurrent(); // compile error
编译器将其翻译为:
WindowsIdentity.GetCurrent()
运行函数GetCurrent()
并返回WindowsIdentity
对象。
(WindowsPrincipal) WindowsIdentity.GetCurrent();
采用WindowsIdentity
对象并将其直接转换为WindowsPrincipal
类型,这是不可以的。
正确的C#代码也需要使用new
关键字:
var wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
编译器将其翻译为:
WindowsIdentity.GetCurrent()
运行函数GetCurrent()
并返回WindowsIdentity
对象。
new WindowsPrincipal(WindowsIdentity.GetCurrent())
创建一个新的WindowsPrincipal
对象,将WindowsIdentity
对象传递给构造函数。现在可以使用。
那为什么要第二个例子:
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
通过执行“错误”操作在PowerShell中工作?因为PowerShell是一种脚本语言,并且可以即时进行解释,并且可以使用 Magic ,所以它可以解释以上内容并执行一些Type Conversion Magic Quote:
基本上,每当您在PowerShell中进行类型转换时,它将执行Magic并尝试每种方法为您动态地动态转换类型。这就是为什么它可以处理您在杂耍者身上扔新的电锯或保龄球的原因。 PowerShell可以解释为我们不是在试图将电锯转换为球,而是将电锯只是另一个对象,并且我们已经知道如何处理对象。
此解释不是.NET的一部分,因此C#无法做到这一点,因此我们必须显式定义所有内容,并正确执行所有操作。这意味着您可以将所有C#和.NET代码转换为有效的PowerShell代码,但不能反过来。